( function( factory ) {
    if ( typeof define === "function" && define.amd ) {
        // AMD. Register as an anonymous module.
        define(["jquery", "knockout"], factory );
    } else {
        // Browser globals
        factory($, ko);
    }
}( function($, ko) {
    + function($) {
        'use strict'

        var Class = function(o) {
            if (!(this instanceof Class) && isFunction(o)) {
                return classify(o)
            }
        }

// Create a new Class.
//
// var SuperPig = Class.create({
// Extends: Animal,
// Implements: Flyable,
// initialize: function() {
// SuperPig.superclass.initialize.apply(this, arguments)
// },
// Statics: {
// COLOR: 'red'
// }
// })
//
        Class.create = function(parent, properties) {
            if (!isFunction(parent)) {
                properties = parent
                parent = null
            }

            properties || (properties = {})
            parent || (parent = properties.Extends || Class)
            properties.Extends = parent

            // The created class constructor
            function SubClass() {
                // Call the parent constructor.
                parent.apply(this, arguments)

                // Only call initialize in self constructor.
                if (this.constructor === SubClass && this.initialize) {
                    this.initialize.apply(this, arguments)
                }
            }

            // Inherit class (static) properties from parent.
            if (parent !== Class) {
                mix(SubClass, parent, parent.StaticsWhiteList)
            }

            // Add instance properties to the subclass.
            implement.call(SubClass, properties)

            // Make subclass extendable.
            return classify(SubClass)
        }

        function implement(properties) {
            var key, value

            for (key in properties) {
                value = properties[key]

                if (Class.Mutators.hasOwnProperty(key)) {
                    Class.Mutators[key].call(this, value)
                } else {
                    this.prototype[key] = value
                }
            }
        }


        // Create a sub Class based on `Class`.
        Class.extend = function(properties) {
            properties || (properties = {})
            properties.Extends = this

            return Class.create(properties)
        }


        function classify(cls) {
            cls.extend = Class.extend
            cls.implement = implement
            return cls
        }


        // Mutators define special properties.
        Class.Mutators = {

            'Extends': function(parent) {
                var existed = this.prototype
                var proto = createProto(parent.prototype)

                // Keep existed properties.
                mix(proto, existed)

                // Enforce the constructor to be what we expect.
                proto.constructor = this

                // Set the prototype chain to inherit from `parent`.
                this.prototype = proto

                // Set a convenience property in case the parent's prototype is
                // needed later.
                this.superclass = parent.prototype
            },

            'Implements': function(items) {
                isArray(items) || (items = [items])
                var proto = this.prototype,
                    item

                while (item = items.shift()) {
                    mix(proto, item.prototype || item)
                }
            },

            'Statics': function(staticProperties) {
                mix(this, staticProperties)
            }
        }


        // Shared empty constructor function to aid in prototype-chain creation.
        function Ctor() {}

        // See: http://jsperf.com/object-create-vs-new-ctor
        var createProto = Object.__proto__ ?
            function(proto) {
                return {
                    __proto__: proto
                }
            } :
            function(proto) {
                Ctor.prototype = proto
                return new Ctor()
            }


        // Helpers
        // ------------

        function mix(r, s, wl) {
            // Copy "all" properties including inherited ones.
            for (var p in s) {
                if (s.hasOwnProperty(p)) {
                    if (wl && indexOf(wl, p) === -1) continue

                    // 在 iPhone 1 代等设备的 Safari 中，prototype 也会被枚举出来，需排除
                    if (p !== 'prototype') {
                        r[p] = s[p]
                    }
                }
            }
        }


        var toString = Object.prototype.toString

        var isArray = Array.isArray || function(val) {
            return toString.call(val) === '[object Array]'
        }

        var isFunction = function(val) {
            return toString.call(val) === '[object Function]'
        }

        var indexOf = Array.prototype.indexOf ?
            function(arr, item) {
                return arr.indexOf(item)
            } :
            function(arr, item) {
                for (var i = 0, len = arr.length; i < len; i++) {
                    if (arr[i] === item) {
                        return i
                    }
                }
                return -1
            }

        $.Class = Class
    }($);

    +function($ ) {

        // var Class = $.Class

        var BaseComponent = $.Class.create({
            initialize: function(element, options, viewModel) {
                this.element = element
                this.id = options['id']
                this.options = options
                this.viewModel = viewModel
                // 绑定事件
                var events = options['events'] || {}
                for(var key in events){
                    if (this.isDomEvent(key)){
                        this.addDomEvent(key, $.getFunction(viewModel,events[key]))
                    }
                    else{
                        this.on(key, $.getFunction(viewModel,events[key]))
                    }
                }
            },
            /**
             * 绑定事件
             *
             * @param {String}
             *            name
             * @param {Function}
             *            callback
             */
            on: function(name, callback) {
                name = name.toLowerCase()
                this._events || (this._events = {})
                var events = this._events[name] || (this._events[name] = [])
                events.push({
                    callback: callback
                })
                return this;
            },
            /**
             * 触发事件
             *
             * @param {String}
             *            name
             */
            trigger: function(name) {
                name = name.toLowerCase()
                if (!this._events || !this._events[name]) return this;
                var args = Array.prototype.slice.call(arguments, 1);
                var events = this._events[name];
                for (var i = 0, count = events.length; i < count; i++) {
                    events[i].callback.apply(this, args);
                }
                return this;

            },
            /**
             * 增加dom事件
             *
             * @param {String}
             *            name
             * @param {Function}
             *            callback
             */
            addDomEvent: function(name, callback){
                $(this.element).on(name, callback)
                return this
            },
            /**
             * 移除dom事件
             *
             * @param {String}
             *            name
             */
            removeDomEvent: function(name){
                $(this.element).off(name)
                return this
            },
            setEnable: function(enable){
                return this
            },
            /**
             * 判断是否为DOM事件
             */
            isDomEvent: function(eventName){
                if (this.element['on' + eventName] === undefined)
                    return false
                else
                    return true
            },
            Statics: {
                compName: '',
                EVENT_VALUE_CHANGE: 'valueChange',
                getName: function() {
                    return this.compName
                }
            }
        })

        $.BaseComponent = BaseComponent

    }($);

    +function($) {
        /**
         * 输入框基类，不可直接使用
         */
        var InputComp = $.BaseComponent.extend({
            initialize: function(element, options, viewModel) {
                InputComp.superclass.initialize.apply(this, arguments)
                this.dataModel = null
                this.hasDataTable = false
                this.parseDataModel()
                this.required = options['required']
                this.maxLength = null
                this.minLength = null
                this.max = null
                this.min = null
                this.regExp = null
                this.placement = options['placement']
                // this.create()
            },
            create: function() {
                var self = this
                if (this.dataModel) {
                    // 处理数据绑定
                    if (this.hasDataTable) {
                        // this.dataModel.ref(this.field).subscribe(function(value)
                        // {
                        // self.modelValueChange(value)
                        // })
                        this.dataModel.on(this.field + "." + $.DataTable.ON_CURRENT_VALUE_CHANGE, function(event){
                            self.modelValueChange(event.newValue);
                        });

                        // 处理只读
                        // this.dataModel.refEnable(this.field).subscribe(function(value)
                        // {
                        // self.setEnable(value)
                        // })
                        // this.dataModel.on($.DataTable.ON_ENABLE_CHANGE,
                        // function(event){
                        // self.setEnable(event.enable);
                        // });

                        // this.dataModel.refRowMeta(this.field,
                        // 'enable').subscribe(function(value) {
                        // self.setEnable(value);
                        // });



                        this.dataModel.on($.DataTable.ON_ENABLE_CHANGE, function(event){
                            if (event.enable === true){
                                var _enable = self.dataModel.getRowMeta(self.field, 'enable');
                                if (_enable === true)
                                    self.setEnable(_enable);
                            }else{
                                self.setEnable(event.enable);
                            }
                        });

                        this.dataModel.on(this.field + '.enable.' +  $.DataTable.ON_CURRENT_META_CHANGE, function(event){
                            self.setEnable(event.newValue);
                        });

                        this.dataModel.on(this.field + '.enable.' +  $.DataTable.ON_ROW_META_CHANGE, function(event){
                            self.setEnable(event.newValue);
                        });

                        // 处理必填
                        // this.dataModel.refRowMeta(this.field,
                        // "required").subscribe(function(value) {
                        // self.setRequired(value)
                        // })
                        this.dataModel.on(this.field + '.required.' +  $.DataTable.ON_CURRENT_META_CHANGE, function(event){
                            self.setRequired(event.newValue);
                        });
                        // this.dataModel.refRowMeta(this.field,
                        // "regExp").subscribe(function(value) {
                        // self.regExp = value
                        // })
                        this.dataModel.on(this.field + '.regExp.' +  $.DataTable.ON_CURRENT_META_CHANGE, function(event){
                            self.regExp =event.newValue;
                        });
                        this.dataModel.on($.DataTable.ON_CURRENT_ROW_CHANGE, function(){
                            var row = self.dataModel.getCurrentRow();
                            if (!row){
                                self.modelValueChange('');
                                self.setEnable(false);
                            }else{
                                self.modelValueChange(row.getValue(self.field));
                                if (this.enable === true){
                                    var _enable = row.getMeta(self.field, 'enable');
                                    if (_enable === true || _enable === 'true' || _enable === false || _enable === 'false') {
                                        self.setEnable(_enable);
                                    }
                                }else{
                                    self.setEnable(this.enable);
                                }
                                self.setRequired(row.getMeta(self.field, 'required'));
                            }
                        });
                        this.dataModel.on($.DataTable.ON_CURRENT_UPDATE, function(event){
                            var row = event.rows[0]
                            self.modelValueChange(row.getValue(self.field));
                        });

                        this.setEnable(this.dataModel.isEnable(this.field))
                        this.setRequired(this.dataModel.getMeta(this.field, "required"))
                        this.regExp = this.dataModel.getMeta(this.field, "regExp")
                    } else {
                        this.dataModel.subscribe(function(value) {
                            self.modelValueChange(value)
                        })
                    }
                    this.modelValueChange(this.hasDataTable ? this.dataModel.getValue(this.field) : this.dataModel())
                }
                if (this.validType)
                    this.validate = $(this.element).validate({
                        single: true,
                        validMode: 'manually',
                        required: this.required,
                        validType: this.validType,
                        placement: this.placement,
                        maxLength: this.maxLength,
                        minLength: this.minLength,
                        max: this.max,
                        min: this.min,
                        maxNotEq: this.maxNotEq,
                        minNotEq: this.minNotEq,
                        reg: this.regExp
                    })

                if (this.element.nodeName == 'INPUT' && (!$(this.element).attr("type") || $(this.element).attr("type") == 'text')) {
                    $(this.element).focusin(function(e) {
                        self.onFocusin ? self.onFocusin(e) : self.setShowValue(self.getValue());
                        $(this).select();
                    })
                    $(this.element).blur(function(e) {
                        if (!self.doValidate() && self._needClean()){
                            if (!self.doValidate() && self._needClean()){
                                if(self.required && (self.element.value === null || self.element.value === undefined || self.element.value === '') ) {
                                    // 因必输项清空导致检验没通过的情况
                                    self.setValue('')
                                } else {
                                    self.element.value = self.getShowValue()
                                }
                            }
                        }
                        else
                            self.setValue(self.element.value)
                    })
                }


            },
            /**
             * 模型数据改变
             *
             * @param {Object}
             *            value
             */
            modelValueChange: function(value) {

            },

            parseDataModel: function() {
                if (!this.options || !this.options["data"]) return
                this.dataModel = $.getJSObject(this.viewModel, this.options["data"])
                if (this.dataModel instanceof $.DataTable) {
                    this.hasDataTable = true
                    this.field = this.options["field"]
                }
            },
            /**
             * 设置模型值
             *
             * @param {Object}
             *            value
             */
            setModelValue: function(value) {
                if (!this.dataModel) return
                if (this.hasDataTable) {
// this.dataModel.setValue(this.field, value, this.dataTableRow)

                    this.dataModel.setValue(this.field, value)
                } else
                    this.dataModel(value)
            },
            /**
             * 设置控件值
             *
             * @param {Object}
             *            value
             */
            setValue: function(value) {},
            /**
             * 取控件的值
             */
            getValue: function() {
                return this.trueValue
            },
            setShowValue: function(showValue) {},
            getShowValue: function() {
                return this.showValue
            },
            setEnable: function(enable) {
                var id = $(this.element).attr('id')
                if (enable === true || enable === 'true') {
                    this.enable = true
                    $(this.element).removeAttr('readonly')
                    $(this.element).parent().removeClass('disablecover').find('.covershade').remove()
                    // if(id != undefined) {
                    // $('[for="'+id+'"]').parent().removeClass('disablecover').find('.covershade').remove()
                    // }
                } else if (enable === false || enable === 'false') {
                    this.enable = false
                    var tmpelement = $(this.element)
                    if(tmpelement.parent().hasClass('disablecover')){ return};
                    tmpelement.attr('readonly', 'readonly')
                    tmpelement.parent().addClass('disablecover').prepend('<div class="covershade"></div>')
                    // if(id != undefined) {
                    // $('[for="'+id+'"]').parent().addClass('disablecover').prepend('<div
                    // class="covershade"></div>')
                    // }
                }
            },
            setRequired: function(required) {
                if (required === true || required === 'true') {
                    this.required = true
                    $(this.element).siblings('.u-mustFlag').show()
                } else if(required === false || required === 'false'){
                    this.required = false
                    $(this.element).siblings('.u-mustFlag').hide()
                }
            },
// setDataTableRow: function(row) {
// this.dataTableRow = row
// },
            /**
             * 校验
             */
            doValidate: function(trueValue){
                if (this.validate){
                    if (trueValue)
                        return this.validate.check(this.getValue())
                    else
                        return this.validate.check()
                } else {
                    return true
                }
            },
            /**
             * 是否需要清除数据
             */
            _needClean: function(){
                if (this.validate)
                    return this.validate._needClean()
                else return false
            },

            Statics: {}
        })

        $.InputComp = InputComp

    }($);
    /*
 * ======================================================================== UUI:
 * dataTable.js
 *
 * ========================================================================
 * Copyright 2015 yonyou, Inc.
 * ========================================================================
 */
    +function($ ) {
        'use strict';

        var Events = function(){
        }

        Events.fn = Events.prototype
        /**
         * 绑定事件
         */
        Events.fn.on = function(name, callback) {
            name = name.toLowerCase()
            this._events || (this._events = {})
            var events = this._events[name] || (this._events[name] = [])
            events.push({
                callback: callback
            })
            return this;
        }

        /**
         * 触发事件
         */
        Events.fn.trigger = function(name) {
            name = name.toLowerCase()
            if (!this._events || !this._events[name]) return this;
            var args =  Array.prototype.slice.call(arguments, 1);
            var events = this._events[name];
            for (var i = 0, count = events.length; i < count; i++) {
                events[i].callback.apply(this, args);
            }
            return this;
        }


        Events.fn.getEvent = function(name){
            name = name.toLowerCase()
            this._events || (this._events = {})
            return this._events[name]
        }

        /**
         * ===========================================================================================================
         *
         * 数据模型
         *
         * ===========================================================================================================
         */

        var DataTable = function(options){
            this.id = options['id']
            this.meta = DataTable.createMetaItems(options['meta'])
            this.enable = options['enable'] || DataTable.DEFAULTS.enable
            this.pageSize = ko.observable(options['pageSize'] || DataTable.DEFAULTS.pageSize)
            this.pageIndex = ko.observable(options['pageIndex'] || DataTable.DEFAULTS.pageIndex)
            this.totalPages = ko.observable(options['totalPages'] || DataTable.DEFAULTS.totalPages)
            this.totalRow = ko.observable()
            this.pageCache = options['pageCache'] === undefined ? DataTable.DEFAULTS.pageCache : options['pageCache']
            this.rows = ko.observableArray([])
            this.selectedIndices = ko.observableArray([])
// this.currSelectedIndex = -1 // ko.observable()
            this._oldCurrentIndex = -1;
            this.focusIndex = -1
            this.hoverIndex = -1
            this.cachedPages = []
            this.createDefaultEvents()
            this.metaChange = {}; // ko.observable(1)
            this.valueChange = ko.observable(1)
            this.enableChange = ko.observable(1)
            this.params = options['params'] || {}
            this.master = options['master'] || ''
        }

        DataTable.fn = DataTable.prototype = new Events()

        DataTable.DEFAULTS = {
            pageSize:10,
            pageIndex:0,
            totalPages:1,
            pageCache:false,
            enable: true
        }

        DataTable.META_DEFAULTS = {
            enable:true,
            required:false,
            descs:{}
        }
        DataTable.createMetaItems = function(metas){
            var newMetas = {};
            for(var key in metas){
                var meta = metas[key]
                if(typeof meta == 'string')
                    meta = {}
                newMetas[key] = $.extend({},DataTable.META_DEFAULTS,meta)
            }
            return newMetas
        }


        // 事件类型
        DataTable.ON_ROW_SELECT = 'select'
        DataTable.ON_ROW_UNSELECT = 'unSelect'
        DataTable.ON_ROW_ALLSELECT = 'allSelect'
        DataTable.ON_ROW_ALLUNSELECT = 'allUnselect'
        DataTable.ON_VALUE_CHANGE = 'valueChange'
        DataTable.ON_CURRENT_VALUE_CHANGE = 'currentValueChange'  // 当前行变化
// DataTable.ON_AFTER_VALUE_CHANGE = 'afterValueChange'
// DataTable.ON_ADD_ROW = 'addRow'
        DataTable.ON_INSERT = 'insert'
        DataTable.ON_UPDATE = 'update'
        DataTable.ON_CURRENT_UPDATE = 'currentUpdate'
        DataTable.ON_DELETE = 'delete'
        DataTable.ON_DELETE_ALL = 'deleteAll'
        DataTable.ON_ROW_FOCUS = 'focus'
        DataTable.ON_ROW_UNFOCUS = 'unFocus'
        DataTable.ON_ROW_HOVER = 'hover'
        DataTable.ON_ROW_UNHOVER = 'unHover'
        DataTable.ON_LOAD = 'load'
        DataTable.ON_ENABLE_CHANGE = 'enableChange'
        DataTable.ON_META_CHANGE = 'metaChange'
        DataTable.ON_ROW_META_CHANGE = 'rowMetaChange'
        DataTable.ON_CURRENT_META_CHANGE = 'currentMetaChange'
        DataTable.ON_CURRENT_ROW_CHANGE = 'currentRowChange'

        DataTable.SUBMIT = {
            current: 'current',
            focus: 'focus',
            all:	'all',
            select:	'select',
            change: 'change',
            empty: 'empty',
            allSelect: 'allSelect',
            allPages: 'allPages'
        }


        DataTable.fn.createDefaultEvents = function(){
            // this.on()
        }

        DataTable.fn.addParam = function(key, value){
            this.params[key] = value
        }

        DataTable.fn.addParams = function(params){
            for(var key in params){
                this.params[key] = params[key]
            }
        }

        DataTable.fn.getParam = function(key){
            return this.params[key]
        }

        /**
         * 获取meta信息，先取row上的信息，没有时，取dataTable上的信息
         *
         * @param {Object}
         *            fieldName
         * @param {Object}
         *            key
         * @param {Object}
         *            row
         */
        DataTable.fn.getMeta = function(fieldName, key){
            if (arguments.length == 0)
                return this.meta
            return this.meta[fieldName][key]
        }

        DataTable.fn.setMeta = function(fieldName, key, value){
            var oldValue = this.meta[fieldName][key]
            var currRow = this.getCurrentRow();
            this.meta[fieldName][key] = value
            if (this.metaChange[fieldName + '.' + key])
                this.metaChange[fieldName + '.' + key](- this.metaChange[fieldName + '.' + key]());
            // this.metaChange(- this.metaChange())
            if (key == 'enable')
                this.enableChange(- this.enableChange())
            this.trigger(DataTable.ON_META_CHANGE, {
                eventType:'dataTableEvent',
                dataTable:this.id,
                field:fieldName,
                meta: key,
                oldValue:oldValue,
                newValue:value
            });
            if (currRow && !currRow.getMeta(fieldName, key, false)){
                this.trigger(fieldName + '.' + key + '.'+ DataTable.ON_CURRENT_META_CHANGE, {
                    eventType:'dataTableEvent',
                    dataTable:this.id,
                    oldValue:oldValue,
                    newValue:value
                });
            }
        }

        DataTable.fn.setCurrentPage = function(pageIndex, notCacheCurrentPage){
            if (pageIndex != this.pageIndex() && notCacheCurrentPage != true)
                this.cacheCurrentPage();
            this.pageIndex(pageIndex)
            var cachedPage = this.cachedPages[this.pageIndex()]
            if(cachedPage) {
                this.removeAllRows()
                this.setRows(cachedPage.rows)
                this.setRowsSelect(cachedPage.selectedIndcies)
            }
        }

        DataTable.fn.isChanged = function(){
            var rows = this.getAllRows()
            for (var i = 0; i < rows.length; i++){
                if (rows[i].status != Row.STATUS.NORMAL)
                    return true
            }
            return false
        }


        /**
         * example: meta: {supplier: {meta: {precision:'3', default: '0239900x',
	 * display:'显示名称'}}}
         */
        DataTable.fn.updateMeta = function(meta){
            if(!meta) {
                return;
            }
            for(var fieldKey in meta) {
                for(var propKey in meta[fieldKey]) {
                    var oldValue = this.meta[fieldKey][propKey]
                    var newValue = meta[fieldKey][propKey]
                    if(propKey === 'default') {
                        if(!this.meta[fieldKey]['default']) {
                            this.meta[fieldKey]['default'] = {}
                        }
                        this.meta[fieldKey]['default'].value = meta[fieldKey][propKey]
                    } else if(propKey === 'display') {
                        if(!this.meta[fieldKey]['default']) {
                            this.meta[fieldKey]['default'] = {}
                        }
                        this.meta[fieldKey]['default'].display = meta[fieldKey][propKey]
                    }else{
                        this.meta[fieldKey][propKey] = meta[fieldKey][propKey]
                    }
                    if (this.metaChange[fieldKey + '.' + propKey])
                        this.metaChange[fieldKey + '.' + propKey](- this.metaChange[fieldKey + '.' + propKey]());

                    this.trigger(DataTable.ON_META_CHANGE, {
                        eventType:'dataTableEvent',
                        dataTable:this.id,
                        field:fieldKey,
                        meta: propKey,
                        oldValue:oldValue,
                        newValue:newValue
                    });
                }

            }
            // this.metaChange(- this.metaChange())
        }


        /**
         * 设置数据
         *
         */
        DataTable.fn.setData = function(data){
            var newIndex = data.pageIndex,
                newSize = data.pageSize || this.pageSize(),
                newTotalPages = data.totalPages || this.totalPages(),
                newTotalRow = data.totalRow,
                select,focus,currPage,
                type = data.type;

// if (newSize != this.pageSize())
// this.cacheRows = []
// else if (this.pageCache)
// this.cacheRows[this.pageIndex()] = this.rows()
            this.pageCache = data.pageCache || this.pageCache
            if (this.pageCache === true){
                this.updatePages(data.pages)
                if (newIndex != this.pageIndex()) {
                    this.setCurrentPage(newIndex, true);
                    this.totalPages(newTotalPages)
                    this.totalRow(newTotalRow)
                    return;
                }
                else{
                    select = this.getPage(newIndex).selectedIndices
                    focus = this.getPage(newIndex).focus
                    this.setRows(this.getPage(newIndex).rows)
                }
            }else{
                select = data.select
                focus = data.focus
                this.setRows(data.rows)
            }
            this.pageIndex(newIndex)
            this.pageSize(newSize)
            this.totalPages(newTotalPages)
            this.totalRow(newTotalRow)

            this.updateSelectedIndices()

            if (select && select.length > 0 && this.rows().length > 0)
                this.setRowsSelect(select)
            if (focus)
                this.setRowFocus(focus)
        }

        /**
         * 清空datatable的所有数据以及分页数据以及index
         */
        DataTable.fn.clear = function(){
            this.removeAllRows();
            this.cachedPages = [];
            this.totalPages(1);
            this.pageIndex(0);
            this.focusIndex = -1;
            this.selectedIndices([]);
        }

        /**
         * 更新分页数据
         */
        DataTable.fn.updatePages = function(pages){
            var pageSize = this.pageSize(),pageIndex = 0, page, r,row;
            var page, index, i, rows, focus, selectIndices, status, j, row, originRow;
            for(i = 0; i< pages.length; i++){
                index = pages[i].index
                rows = pages[i].rows
                focus = pages[i].current
                selectIndices = pages[i].select
                status = pages[i].status
                if (status === 'del'){
                    this.cachedPages[index] = null;
                    continue;
                }
                if (!this.cachedPages[index]){
                    page = new Page({parent:this})
                    page.rows = rows;
                    for (var j = 0; j< page.rows.length; j++){
                        page.rows[j].rowId =  page.rows[j].id
                        delete page.rows[j].id
                    }
                    this.cachedPages[index] = page
                }else{
                    // 如果是当前页，先把this.rows数据更新到page中
                    if (index == this.pageIndex()){
                        this.cacheCurrentPage();
                    }
                    page = this.cachedPages[index]
                    for(var j=0; j<rows.length; j++) {
                        r = rows[j];
                        if (!r.id)
                            r.id = Row.getRandomRowId()
                        if (r.status == Row.STATUS.DELETE){
                            this.removeRowByRowId(r.id)
                        }else {
                            row = page.getRowByRowId(r.id)
                            if (row){
                                page.updateRow(row, r);
                            }else{
                                r.rowId = r.id
                                delete r.id
                                page.rows.push(r);
                            }
                        }
                    }
                }
                page.selectedIndices = selectIndices;
                page.focus = focus;
            }
        }

        /**
         * 设置行数据
         *
         * @param {Object}
         *            rows
         */
        DataTable.fn.setRows = function(rows){
            var insertRows = [],_id;
            for (var i = 0; i < rows.length; i++){
                var r = rows[i]
                _id = r.rowId || r.id;
                if (!_id)
                    _id = Row.getRandomRowId()
                if (r.status == Row.STATUS.DELETE){
                    this.removeRowByRowId(_id)
                }
                else{
                    var row = this.getRowByRowId(_id)
                    if (row){
                        row.updateRow(r)
                        if (!$.isEmptyObject(r.data)) {
                            this.trigger(DataTable.ON_UPDATE,{
                                index:i,
                                rows:[row]
                            })
                            if (row == this.getCurrentRow()) {
                                this.valueChange(-this.valueChange())
                                row.valueChange(-row.valueChange())
                                this.trigger(DataTable.ON_CURRENT_UPDATE,{
                                    index:i,
                                    rows:[row]
                                })
                            } else {
                                row.valueChange(-row.valueChange())
                            }
                        }

                    }
                    else{
                        row = new Row({parent:this,id:_id})
                        row.setData(rows[i])
                        insertRows.push(row)
// this.addRow(row)
                    }
                }
            }
            if (insertRows.length > 0)
                this.addRows(insertRows)
        }

        DataTable.fn.clearCache = function(){
            this.cachedPages = []
        }

        DataTable.fn.cacheCurrentPage = function(){
            if(this.pageCache && this.pageIndex() > -1) {
                var page = new Page({parent:this});
                page.focus = this.getFocusIndex();
                page.selectedIndices = this.selectedIndices().slice();
                var rows = this.rows().slice();
                for (var i = 0; i<rows.length; i++){
                    var r = rows[i].getData();
                    r.rowId = r.id;
                    delete r.id;
                    page.rows.push(r)
                }
                // page.rows = this.rows().slice();
                this.cachedPages[this.pageIndex()] = page
            }
        }

        /**
         * 前端分页方法，不建议使用，建议在后端进行分页
         *
         * @param allRows
         */
        DataTable.fn.setPages = function(allRows){
            var pageSize = this.pageSize(),pageIndex = 0, page;
            this.cachedPages = [];
            for (var i = 0; i< allRows.length; i++){
                pageIndex = Math.floor(i/pageSize);
                if (!this.cachedPages[pageIndex]){
                    page = new Page({parent:this})
                    this.cachedPages[pageIndex] = page
                }
                page.rows.push(allRows[i])
            }
            if (this.pageIndex() > -1)
                this.setCurrentPage(this.pageIndex());
            this.totalRow(allRows.length);
            this.totalPages(pageIndex + 1);
        }

        DataTable.fn.hasPage = function(pageIndex){
            // return (this.pageCache && this.cachedPages[pageIndex] &&
            // this.cachedPages[pageIndex].pageSize == this.pageSize()) ? true :
            // false
            return (this.pageCache && this.cachedPages[pageIndex]) ? true : false
        }

        DataTable.fn.getPage = function(pageIndex){
            if (this.pageCache){
                return this.cachedPages[pageIndex]
            }
            return -1;
        }

        DataTable.fn.getPages = function(){
            if (this.pageCache){
                return this.cachedPages
            }
            return [];
        }

        DataTable.fn.copyRow = function(index, row){
            var newRow = new Row({parent:this})
            if(row) {
                newRow.setData(row.getData())
            }
            this.insertRows(index === undefined ? this.rows().length : index, [newRow])
        }

        /**
         * 追加行
         */
        DataTable.fn.addRow = function(row){
            this.insertRow(this.rows().length, row)
        }

        /**
         * 追加多行
         */
        DataTable.fn.addRows = function(rows){
            this.insertRows(this.rows().length, rows)
        }

        DataTable.fn.insertRow = function(index, row){
            if(!row){
                row = new Row({parent:this})
            }
            this.insertRows(index, [row])
        }

        DataTable.fn.insertRows = function(index, rows){
// if (this.onBeforeRowInsert(index,rows) == false)
// return
            var args = [index, 0]
            for ( var i = 0; i < rows.length; i++) {
                args.push(rows[i]);
            }
            this.rows.splice.apply(this.rows, args);

            this.updateSelectedIndices(index, '+', rows.length)
            this.updateFocusIndex(index, '+', rows.length)

            this.trigger(DataTable.ON_INSERT,{
                index:index,
                rows:rows
            })
        }

        /**
         * 创建空行
         */
        DataTable.fn.createEmptyRow = function(){
            var r = new Row({parent:this})
            this.addRow(r)
            return r
        }

        DataTable.fn.removeRowByRowId = function(rowId){
            var index = this.getIndexByRowId(rowId)
            if (index != -1)
                this.removeRow(index)
        }

        DataTable.fn.removeRow = function(index) {
            if (index instanceof Row){
                index = this.getIndexByRowId(index.rowId)
            }
            this.removeRows([ index ]);
        }

        DataTable.fn.removeAllRows = function(){
            this.rows([])
            this.selectedIndices([])
            this.focusIndex = -1
            this.trigger(DataTable.ON_DELETE_ALL)
            this.updateCurrIndex();
        }

        DataTable.fn.removeRows = function(indices) {
            indices = this._formatToIndicesArray(indices)
            indices = indices.sort()
            var rowIds = [], rows = this.rows(), deleteRows = [];
            for (var i = indices.length - 1; i >= 0; i--) {
                var index = indices[i]
                var delRow = rows[index];
                if (delRow == null) {
                    continue;
                }
                rowIds.push(delRow.rowId)
                var deleteRow = rows.splice(index, 1);
                deleteRows.push(deleteRow[0]);
                this.updateSelectedIndices(index,'-')
                this.updateFocusIndex(index, '-')
            }
            this.rows(rows)
            this.deleteRows = deleteRows;
            this.trigger(DataTable.ON_DELETE,{
                indices:indices,
                rowIds:rowIds,
                deleteRows:deleteRows
            })
            this.updateCurrIndex();
        }

        /**
         * 设置行删除
         *
         * @param {Object}
         *            index
         */
        DataTable.fn.setRowDelete = function(index){
            if (index instanceof Row){
                index = this.getIndexByRowId(index.rowId)
            }
            this.setRowDelete([index])
        }

        /**
         * 设置所有行删除
         */
        DataTable.fn.setAllRowsDelete = function(){
            var indices = new Array(this.rows().length)
            for (var i = 0; i < indices.length; i++) {
                indices[i] = i
            }
            this.setRowsDelete(indices)
        }

        /**
         * 设置行删除
         *
         * @param {Array}
         *            indices
         */
        DataTable.fn.setRowsDelete = function(indices){
            indices = this._formatToIndicesArray(indices)
            for (var i=0; i< indices.length; i++){
                var row = this.getRow(indices[i])
                if (row.status == Row.STATUS.NEW){
                    this.rows(this.rows().splice(indices[i], 1));
                    this.updateSelectedIndices(indices[i],'-')
                    this.updateFocusIndex(index, '-')
                }
                else{
                    row.status = Row.STATUS.FALSE_DELETE
                }
            }
            var rowIds = this.getRowIdsByIndices(indices)
            this.trigger(DataTable.ON_ROW_DELETE, {
                falseDelete: true,
                indices:indices,
                rowIds:rowIds
            })
        }

        DataTable.fn.setAllRowsSelect = function() {
            var indices = new Array(this.rows().length)
            for (var i = 0; i < indices.length; i++) {
                indices[i] = i
            }
            this.setRowsSelect(indices)
            this.trigger(DataTable.ON_ROW_ALLSELECT, {
            })
        }

        /**
         * 设置选中行，清空之前已选中的所有行
         */
        DataTable.fn.setRowSelect = function(index){
            if (index instanceof Row){
                index = this.getIndexByRowId(index.rowId)
            }
            this.setRowsSelect([index])
            this.setRowFocus(this.getSelectedIndex())
        }

        DataTable.fn.setRowsSelect = function(indices){
            indices = indices || -1;
            if (indices == -1){
                this.setAllRowsUnSelect({quiet:true})
                return;
            }
            indices = this._formatToIndicesArray(indices)
            var sIns = this.selectedIndices()
            if($.type(indices) == 'array' && $.type(sIns) == 'array' && indices.join() == sIns.join()) {
                // 避免与控件循环触发
                return;
            }
            this.setAllRowsUnSelect({quiet:true})
            this.selectedIndices(indices)
// var index = this.getSelectedIndex()
// this.setCurrentRow(index)
            var rowIds = this.getRowIdsByIndices(indices)
            this.valueChange(- this.valueChange())
            this.trigger(DataTable.ON_ROW_SELECT, {
                indices:indices,
                rowIds:rowIds
            })
            this.updateCurrIndex();
        }
        DataTable.fn.addRowSelect = function (index) {
            if (index instanceof Row) {
                index = this.getIndexByRowId(index.rowId);
            }
            this.addRowsSelect([index]);
        };
        /**
         * 添加选中行，不会清空之前已选中的行
         */
        DataTable.fn.addRowsSelect = function(indices){
            indices = this._formatToIndicesArray(indices)
            var selectedIndices = this.selectedIndices().slice()
            for (var i=0; i< indices.length; i++){
                var ind = indices[i], toAdd = true
                for(var j=0; j< selectedIndices.length; j++) {
                    if(selectedIndices[j] == ind) {
                        toAdd = false
                    }
                }
                if(toAdd) {
                    selectedIndices.push(indices[i])
                }
            }
            this.selectedIndices(selectedIndices)
// var index = this.getSelectedIndex()
// this.setCurrentRow(index)
            var rowIds = this.getRowIdsByIndices(indices)
            this.trigger(DataTable.ON_ROW_SELECT, {
                indices:indices,
                rowIds:rowIds
            })
            this.updateCurrIndex();
        }

        /**
         * 根据索引取rowid
         *
         * @param {Object}
         *            indices
         */
        DataTable.fn.getRowIdsByIndices = function(indices){
            var rowIds = []
            for(var i=0; i<indices.length; i++){
                rowIds.push(this.getRow(indices[i]).rowId)
            }
            return rowIds
        }

        /**
         * row的index
         *
         * @param {Object}
         *            row
         */
        DataTable.fn.indexOf = function(row){
            var rows = this.rows();
            for (var i=0, count = rows.length; i< count; i++){
                if (rows[i] == row)
                    return i
            }
            return -1
        }

        /**
         * 全部取消选中
         */
        DataTable.fn.setAllRowsUnSelect = function(options){
            this.selectedIndices([])
            if( !(options && options.quiet) ) {
                this.trigger(DataTable.ON_ROW_ALLUNSELECT)
            }
            this.updateCurrIndex();
        }

        /**
         * 取消选中
         */
        DataTable.fn.setRowUnSelect = function(index){
            this.setRowsUnSelect([index])
        }

        DataTable.fn.setRowsUnSelect = function(indices){
            indices = this._formatToIndicesArray(indices)
            var selectedIndices = this.selectedIndices().slice()

            // 避免与控件循环触发
            if(selectedIndices.indexOf(indices[0]) == -1) return;

            for(var i=0; i<indices.length; i++){
                var index = indices[i]
                var pos = selectedIndices.indexOf(index)
                if (pos != -1)
                    selectedIndices.splice(pos,1)
            }
            this.selectedIndices(selectedIndices)
            var rowIds = this.getRowIdsByIndices(indices)
            this.trigger(DataTable.ON_ROW_UNSELECT, {
                indices:indices,
                rowIds:rowIds
            })
            this.updateCurrIndex();
        }

        /**
         *
         * @param {Object}
         *            index 要处理的起始行索引
         * @param {Object}
         *            type 增加或减少 + -
         */
        DataTable.fn.updateSelectedIndices = function(index, type, num){
            if(!$.isNumeric(num)) {
                num = 1
            }
            var selectedIndices = this.selectedIndices().slice()
            if (selectedIndices == null || selectedIndices.length == 0)
                return
            for (var i = 0, count= selectedIndices.length; i< count; i++){
                if (type == '+'){
                    if (selectedIndices[i] >= index)
                        selectedIndices[i] = parseInt(selectedIndices[i]) + num
                }
                else if (type == '-'){
                    if( selectedIndices[i] >= index &&  selectedIndices[i] <= index+num-1 ){
                        selectedIndices.splice(i,1)
                    }
                    else if(selectedIndices[i] > index+num-1)
                        selectedIndices[i] = selectedIndices[i] - num
                }
            }
            this.selectedIndices(selectedIndices)
// var currIndex = this.getSelectedIndex()
// this.setCurrentRow(currIndex)
        }

        DataTable.fn.updateFocusIndex = function(opIndex, opType, num) {
            if(!$.isNumeric(num)) {
                num = 1
            }
            if(opIndex <= this.focusIndex && this.focusIndex != -1) {
                if(opType === '+') {
                    this.focusIndex += num
                } else if(opType === '-') {
                    if(this.focusIndex >= opIndex && this.focusIndex <= opIndex+num-1 ) {
                        this.focusIndex = -1
                    } else if(this.focusIndex > opIndex+num-1){
                        this.focusIndex -= num
                    }
                }
            }
        }

        /**
         * 获取选中行索引，多选时，只返回第一个行索引
         */
        DataTable.fn.getSelectedIndex = function(){
            var selectedIndices = this.selectedIndices()
            if (selectedIndices == null || selectedIndices.length == 0)
                return -1
            return selectedIndices[0]
        }

        DataTable.fn.getSelectedIndexs = function(){
            var selectedIndices = this.selectedIndices()
            if (selectedIndices == null || selectedIndices.length == 0)
                return []
            return selectedIndices
        }

        /**
         * 获取焦点行
         */
        DataTable.fn.getFocusIndex = function(){
            return this.focusIndex
        }

        /**
         * 根据行号获取行索引
         *
         * @param {String}
         *            rowId
         */
        DataTable.fn.getIndexByRowId = function(rowId){
            var rows = this.rows();
            for (var i=0, count = rows.length; i< count; i++){
                if (rows[i].rowId == rowId)
                    return i
            }
            return -1
        }

        /**
         * 获取所有行数据
         */
        DataTable.fn.getAllDatas = function(){
            var rows = this.getAllRows()
            var datas = []
            for (var i=0, count = rows.length; i< count; i++)
                if (rows[i])
                    datas.push(rows[i].getData())
            return datas
        }

        /**
         * 获取当前页数据
         */
        DataTable.fn.getData = function(){
            var datas = [],rows = this.rows();
            for(var i = 0; i< rows.length; i++){
                datas.push(rows[i].getData())
            }
            return datas
        }

        DataTable.fn.getDataByRule = function(rule){
            var returnData = {},datas = null,rows;
            returnData.meta = this.meta
            returnData.params = this.params
            rule = rule || DataTable.SUBMIT.current
            if(rule == DataTable.SUBMIT.current){
                datas = []
                var currIndex = this.focusIndex
                if (currIndex == -1)
                    currIndex = this.getSelectedIndex()
                rows = this.rows();
                for (var i =0, count = rows.length; i< count; i++){
                    if (i == currIndex)
                        datas.push(rows[i].getData())
                    else
                        datas.push(rows[i].getEmptyData())
                }

            }
            else if (rule == DataTable.SUBMIT.focus){
                datas = []
                rows = this.rows();
                for (var i =0, count = rows.length; i< count; i++){
                    if (i == this.focusIndex)
                        datas.push(rows[i].getData())
                    else
                        datas.push(rows[i].getEmptyData())
                }
            }
            else if (rule == DataTable.SUBMIT.all){
                datas = this.getData()
            }
            else if (rule == DataTable.SUBMIT.select){
                datas = this.getSelectedDatas(true)
            }
            else if (rule == DataTable.SUBMIT.change){
                datas = this.getChangedDatas()
            }
            else if(rule === DataTable.SUBMIT.empty){
                datas = []
            }
            if (this.pageCache && datas != null) {
                datas = [{index:this.pageIndex(), select:this.getSelectedIndexs(),focus:this.focusIndex,rows:datas}]
            }
            if (rule == DataTable.SUBMIT.allSelect){
                datas = []
                var totalPages = this.totalPages();
                // 缓存页数据
                for (var i = 0 ; i <totalPages; i++){
                    if (i == this.pageIndex()){
                        // 当前页数据
                        datas.push({index:this.pageIndex(), select:this.getSelectedIndexs(),focus:this.focusIndex,rows:this.getSelectedDatas()});
                    }else{
                        var page = this.cachedPages[i];
                        if (page){
                            datas.push({index:i,select:page.selectedIndices,focus:page.focus,rows:page.getSelectDatas()});
                        }
                    }
                }
            }else if (rule == DataTable.SUBMIT.allPages){
                datas = []
                var totalPages = this.totalPages();
                // 缓存页数据
                for (var i = 0 ; i <totalPages; i++){
                    if (i == this.pageIndex()){
                        // 当前页数据
                        datas.push({index:this.pageIndex(), select:this.getSelectedIndexs(),focus:this.focusIndex,rows:this.getData()});
                    }else{
                        var page = this.cachedPages[i];
                        if (page){
                            datas.push({index:i,select:page.selectedIndices,focus:page.focus,rows:page.getData()});
                        }
                    }
                }
            }
            if (this.pageCache){
                returnData.pages = datas;
            }else{
                returnData.rows = datas
                returnData.select= this.getSelectedIndexs()
                returnData.focus = this.getFocusIndex()
            }

            returnData.pageSize = this.pageSize()
            returnData.pageIndex = this.pageIndex()
            returnData.isChanged = this.isChanged()
            returnData.master = this.master
            returnData.pageCache = this.pageCache
            return returnData
        }

        /**
         * 获取选中行数据
         */
        DataTable.fn.getSelectedDatas = function(withEmptyRow){
            var selectedIndices = this.selectedIndices()
            var datas = []
            var sIndices = []
            for(var i = 0, count=selectedIndices.length; i< count; i++){
                sIndices.push(selectedIndices[i])
            }
            var rows = this.rows();
            for(var i = 0, count=rows.length; i< count; i++){
                if (sIndices.indexOf(i) != -1)
                    datas.push(rows[i].getData())
                else if (withEmptyRow == true)
                    datas.push(rows[i].getEmptyData())
            }
            return datas
        }
        DataTable.fn.getSelectedRows = function () {
            var selectedIndices = this.selectedIndices();
            var selectRows = [];
            var rows = this.rows.peek();
            var sIndices = [];
            for (var i = 0, count = selectedIndices.length; i < count; i++) {
                sIndices.push(selectedIndices[i]);
            }
            for (var i = 0, count = rows.length; i < count; i++) {
                if (sIndices.indexOf(i) != -1) selectRows.push(rows[i]);
            }
            return selectRows;
        }

        DataTable.fn.refSelectedRows = function(){
            return ko.pureComputed({
                read: function(){
                    var ins = this.selectedIndices() || []
                    var rs = this.rows()
                    var selectedRows = []
                    for(var i=0;i<ins.length;i++) {
                        selectedRows.push(rs[i])
                    }
                    return selectedRows
                },owner: this
            })
        }

        /**
         * 绑定字段值
         *
         * @param {Object}
         *            fieldName
         */
        DataTable.fn.ref = function(fieldName){
            return ko.pureComputed({
                read: function(){
                    this.valueChange()
                    var row = this.getCurrentRow()
                    if (row)
                        return row.getValue(fieldName)
                    else
                        return ''
                },
                write: function(value){
                    var row = this.getCurrentRow()
                    if (row)
                        row.setValue(fieldName,value)
                },
                owner: this
            })
        }

        /**
         * 绑定字段属性
         *
         * @param {Object}
         *            fieldName
         * @param {Object}
         *            key
         */
        DataTable.fn.refMeta = function(fieldName, key){
            if (!this.metaChange[fieldName + '.' + key])
                this.metaChange[fieldName + '.' + key] = ko.observable(1);
            return ko.pureComputed({
                read: function(){
                    this.metaChange[fieldName + '.' + key]()
                    return this.getMeta(fieldName, key)
                },
                write: function(value){
                    this.setMeta(fieldName, key, value)
                },
                owner: this
            })
        }

        DataTable.fn.refRowMeta = function(fieldName, key){
            if (!this.metaChange[fieldName + '.' + key])
                this.metaChange[fieldName + '.' + key] = ko.observable(1);
            return ko.pureComputed({
                read: function(){
                    this.metaChange[fieldName + '.' + key]()
                    var row = this.getCurrentRow()
                    if (row)
                        return row.getMeta(fieldName, key)
                    else
                        return this.getMeta(fieldName, key)
                },
                write: function(value){
                    var row = this.getCurrentRow()
                    if (row)
                        row.setMeta(fieldName,value)
                },
                owner: this
            })
        }

        DataTable.fn.getRowMeta = function(fieldName, key){
            var row = this.getCurrentRow()
            if (row)
                return row.getMeta(fieldName, key)
            else
                return this.getMeta(fieldName, key)
        }

        DataTable.fn.refEnable = function(fieldName){
            return ko.pureComputed({
                read: function(){
                    this.enableChange()
                    if (!fieldName)
                        return this.enable
                    var fieldEnable = this.getMeta(fieldName, 'enable')
                    if (typeof fieldEnable == 'undefined' || fieldEnable == null)
                        fieldEnable = true
                    return fieldEnable && this.enable
// return this.enable && (this.getMeta(fieldName, 'enable') || false)
                },
                owner: this
            })
        }

        DataTable.fn.isEnable = function(fieldName){
            var fieldEnable = this.getMeta(fieldName, 'enable')
            if (typeof fieldEnable == 'undefined' || fieldEnable == null)
                fieldEnable = true
            return fieldEnable && this.enable
        }

        DataTable.fn.getValue = function(fieldName,row){
            row = row || this.getCurrentRow()
            if (row)
                return row.getValue(fieldName)
            else
                return ''
        }

        DataTable.fn.setValue = function(fieldName, value, row, ctx){
            row = row ? row : this.getCurrentRow()
            if (row)
                row.setValue(fieldName, value, ctx)
        }

        DataTable.fn.setEnable = function(enable){
            if (this.enable == enable) return
            this.enable = enable
            this.enableChange(- this.enableChange())
            this.trigger(DataTable.ON_ENABLE_CHANGE,{
                enable:this.enable
            })
        }

        /**
         * 获取当前操作行 规则： focus 行优先，没有focus行时，取第一选中行
         */
        DataTable.fn.getCurrentRow = function(){
            if (this.focusIndex != -1)
                return this.getFocusRow()
            var index  = this.getSelectedIndex()
            if (index == -1)
                return null
            else
                return this.getRow(index)
        }


        DataTable.fn.updateCurrIndex = function(){
            var currentIndex = this.focusIndex != -1 ? this.focusIndex : this.getSelectedIndex();
            if (this._oldCurrentIndex != currentIndex){
                this._oldCurrentIndex = currentIndex;
                this.trigger(DataTable.ON_CURRENT_ROW_CHANGE)
            }
        }

        /**
         * 获取焦点行
         */
        DataTable.fn.getFocusRow = function(){
            if (this.focusIndex != -1)
                return this.getRow(this.focusIndex)
            else
                return null
        }

        /**
         * 设置焦点行
         *
         * @param {Object}
         *            index 行对象或者行index
         * @param quiet
         *            不触发事件
         * @param force
         *            当index行与已focus的行相等时，仍然触发事件
         */
        DataTable.fn.setRowFocus = function(index, quiet, force){
            var rowId = null
            if(index instanceof Row) {
                index = this.getIndexByRowId(index.rowId)
                rowId = index.rowId
            }
            if(index === -1 || (index === this.focusIndex && !force) ) {
                return;
            }
            this.focusIndex = index
            if(quiet) {
                return;
            }
            this.valueChange(- this.valueChange())
            if (!rowId){
                rowId = this.getRow(index).rowId
            }
            this.trigger(DataTable.ON_ROW_FOCUS, {
                index:index,
                rowId:rowId
            })
            this.updateCurrIndex();
        }

        /**
         * 焦点行反选
         */
        DataTable.fn.setRowUnFocus = function(){
            this.valueChange(- this.valueChange())
            var indx = this.focusIndex,rowId = null;
            if (indx !== -1){
                rowId = this.getRow(indx).rowId
            }
            this.trigger(DataTable.ON_ROW_UNFOCUS, {
                index:indx,
                rowId:rowId
            })
            this.focusIndex = -1
            this.updateCurrIndex();
        }

        DataTable.fn.getHoverRow = function(){
            return this.getRow(this.hoverIndex)
        }

        DataTable.fn.getHoverIndex = function(){
            return this.hoverIndex
        }


        DataTable.fn.setRowHover = function(index){
            var rowId = null
            if(index instanceof Row) {
                index = this.getIndexByRowId(index.rowId)
                rowId = index.rowId
            }
            if(index === -1 || index === this.hoverIndex) {
                return;
            }
            this.hoverIndex = index

            if (!rowId){
                rowId = this.getRow(index).rowId
            }
            this.trigger(DataTable.ON_ROW_HOVER, {
                index:index,
                rowId:rowId
            })
        }

        DataTable.fn.setRowUnHover = function(){
            var indx = this.hoverIndex,rowId = null;
            if (indx !== -1){
                rowId = this.getRow(indx).rowId
            }
            this.trigger(DataTable.ON_ROW_UNHOVER, {
                index:indx,
                rowId:rowId
            })
            this.hoverIndex = -1
        }

        DataTable.fn.getRow = function(index){
            // return this.rows()[index] //modify by licza. improve performance
            return this.rows.peek()[index]
        }

        DataTable.fn.getAllRows = function(){
            return this.rows()
        }

        DataTable.fn.getAllPageRows = function(){
            var datas = [],rows;
            for(var i=0; i< this.totalPages(); i++){
                rows = [];
                if (i == this.pageIndex()){
                    rows = this.getData();
                }else{
                    var page = this.cachedPages[i];
                    if (page){
                        rows = page.getData();
                    }
                }
                for(var j = 0; j< rows.length; j++){
                    datas.push(rows[j]);
                }
            }
            return datas;
        }

        DataTable.fn.getRowByRowId = function(rowid){
            var rows = this.rows();
            for(var i=0, count= rows.length; i<count; i++){
                if (rows[i].rowId == rowid)
                    return rows[i]
            }
            return null
        }

        /**
         * 获取变动的数据(新增、修改)
         */
        DataTable.fn.getChangedDatas = function(withEmptyRow){
            var datas = [], rows=this.rows();
            for (var i=0, count = rows.length; i< count; i++){
                if (rows[i] && rows[i].status != Row.STATUS.NORMAL){
                    datas.push(rows[i].getData())
                }
                else if (withEmptyRow == true){
                    datas.push(rows[i].getEmptyData())
                }
            }
            return datas
        }

        DataTable.fn._formatToIndicesArray = function(indices){
            if (typeof indices == 'string' || typeof indices == 'number') {
                indices = [indices]
            } else if (indices instanceof Row){
                indices = this.getIndexByRowId(indices.rowId)
            } else if ($.type(indices) === 'array' && indices.length > 0 && indices[0] instanceof Row){
                for (var i = 0; i < indices.length; i++) {
                    indices[i] = this.getIndexByRowId(indices[i].rowId)
                }
            }
            return indices;
        }

        /**
         * row : {data:{}}
         *
         * @constructor
         */
        var Page = function(options){
            this.focus = options['focus'] || null;
            this.selectedIndices = options['selectedIndices']  || null;
            this.rows = options['rows'] || []
            this.parent = options['parent'] || null;
        }

        Page.fn = Page.prototype

        Page.fn.getData = function(){
            var datas = [],row,meta;
            meta = this.parent.getMeta()
            for(var i=0; i< this.rows.length; i++){
                row = this.rows[i];
                datas.push({'id':row.rowId ,'status': row.status, data: row.data});
            }
            return datas
        }

        Page.fn.getSelectDatas = function(){
            var datas = [],row;
            for(var i=0; i< this.rows.length; i++){
                row = this.rows[i];
                datas.push({'id':row.rowId ,'status': row.status, data: row.data});
            }
            for (var i=0; i< this.selectedIndices.length; i++){
                row = this.rows[this.selectedIndices[i]];
                datas.push({'id':row.rowId ,'status': row.status, data: row.data});
            }
            return datas
        }

        Page.fn.getRowByRowId = function(rowid){
            for(var i=0, count= this.rows.length; i<count; i++){
                if (this.rows.rowId == rowid)
                    return this.rows[i]
            }
            return null
        }

        Page.fn.removeRowByRowId = function(rowid){
            for(var i=0, count= this.rows.length; i<count; i++){
                if (this.rows.rowId == rowid)
                    this.rows.splice(i,1);
            }
        }

        Page.fn.getSelectRows = function(){
            var rows = [];
            for (var i=0; i< this.selectedIndices.length; i++){
                rows.push(this.rows[this.selectedIndices[i]])
            }
            return rows
        }

        Page.fn.getRowByRowId = function(rowid){
            for(var i=0, count= this.rows.length; i<count; i++){
                if (this.rows[i].rowId == rowid)
                    return this.rows[i]
            }
            return null
        }

        Page.fn.setRowValue = function(rowIndex, fieldName, value){
            var row = this.rows[rowIndex]
            if (row){
                row.data[fieldName]['value'] = value
                if (row.status != Row.STATUS.NEW)
                    row.status = Row.STATUS.UPDATE
            }
        }

        Page.fn.getRowValue = function(rowIndex, fieldName){
            var row = this.rows[rowIndex]
            if (row){
                return row.data[fieldName]['value']
            }
            return null
        }

        Page.fn.setRowMeta = function(rowIndex, fieldName, metaName, value){
            var row = this.rows[rowIndex]
            if (row){
                var meta = row[fieldName].meta
                if (!meta)
                    meta = row[fieldName].meta = {}
                meta[metaName] = value
                if (row.status != Row.STATUS.NEW)
                    row.status = Row.STATUS.UPDATE
            }
        }

        Page.fn.getRowMeta = function(rowIndex, fieldName, metaName){
            var row = this.rows[rowIndex]
            if (row){
                var meta = row[fieldName].meta
                if (!meta)
                    return null
                else
                    return meta[metaName]
            }
            return null
        }


        Page.fn.updateRow = function(originRow, newRow){
            originRow.status = originRow.status
            // this.rowId = data.rowId
            if (!newRow.data) return;
            for(var key in newRow.data){
                if (originRow.data[key]){
                    var valueObj = newRow.data[key]
                    if (typeof valueObj == 'string' || typeof valueObj == 'number' || valueObj === null)
                        originRow.data[key]['value'] = valueObj
                    // this.setValue(key, this.formatValue(key, valueObj))
                    else{
// this.setValue(key, valueObj.value)

                        if(valueObj.error){
                            $.showMessageDialog({title:"警告",msg:valueObj.error,backdrop:true});
                        }else{
                            // this.setValue(key, this.formatValue(key,
                            // valueObj.value), null)
                            originRow.data[key]['value'] = valueObj.value
                            for(var k in valueObj.meta){
                                originRow.data[key]['meta'] = originRow.data[key]['meta'] || {}
                                originRow.data[key]['meta'][k] = valueObj.meta[k]
                            }
                        }
                    }
                }
            }
        }


        /**
         * ===========================================================================================================
         *
         * 行模型
         *
         * {id:'xxx', parent:dataTable1}
         *
         * data:{value:'v1',meta:{}}
         *
         * ===========================================================================================================
         */
        var Row = function(options){
            this.rowId = options['id'] || Row.getRandomRowId()
            this.status = Row.STATUS.NEW
            this.parent = options['parent']
            this.initValue = null
            this.data = {}
            this.metaChange = {}// ko.observable(1)
            this.valueChange = ko.observable(1)
            // add by songhlc 添加新的代码
            this.selected = ko.pureComputed({
                read: function read() {
                    var rows = this.parent.rows.peek();
                    var index = -1
                    for (var i = 0, count = rows.length; i < count; i++) {
                        if (rows[i].rowId === this.rowId) {
                            index = i
                        }
                    }
                    var selectedIndices = this.parent.selectedIndices();
                    if (selectedIndices == null || selectedIndices.length == 0) {
                        selectedIndices = []
                    }
                    return selectedIndices.indexOf(index) != -1;
                },
                owner: this
            });
            this.init()
        }

        Row.STATUS = {
            NORMAL: 'nrm',
            UPDATE: 'upd',
            NEW: 'new',
            DELETE: 'del',
            FALSE_DELETE: 'fdel'
        }

        Row.fn = Row.prototype = new Events()

        /**
         * Row初始化方法
         *
         * @private
         */
        Row.fn.init = function(){
            var meta = this.parent.meta
            // 添加默认值
            for (var key in meta){
                this.data[key] = {}
                if (meta[key]['default']){
                    var defaults = meta[key]['default']
                    for (var k in defaults){
                        if (k == 'value')
                            this.data[key].value = defaults[k]
                        else{
                            this.data[key].meta = this.data[key].meta || {}
                            this.data[key].meta[k] = defaults[k]
                        }
                    }
                }
            }
        }

        Row.fn.ref = function(fieldName){
            return ko.pureComputed({
                read: function(){

                    this.valueChange()
                    return this._getField(fieldName)['value']
                },
                write: function(value){
                    this.setValue(fieldName, value)
                },
                owner: this
            })
        }

        Row.fn.refMeta = function(fieldName, key){
            if (!this.metaChange[fieldName + '.' + key])
                this.metaChange[fieldName + '.' + key] = ko.observable(1);
            return ko.pureComputed({
                read: function(){
                    this.metaChange[fieldName + '.' + key]()
                    return this.getMeta(fieldName, key)
                },
                write: function(value){
                    this.setMeta(fieldName, key, value)
                },
                owner: this
            })
        }
        Row.fn.refCombo = function(fieldName,datasource){
            return ko.pureComputed({
                read: function(){
                    this.valueChange()
                    var ds = $.getJSObject(this.parent.parent,datasource)
                    if(this._getField(fieldName)['value'] === undefined || this._getField(fieldName)['value'] === "" ) return "";
                    var v = this._getField(fieldName)['value'];
                    var valArr = typeof v === 'string' ? v.split(',') : [v];

                    var nameArr = []

                    for( var i=0,length=ds.length; i<length; i++){
                        for(var j=0; j<valArr.length;j++){
                            if(ds[i].pk == valArr[j]){
                                nameArr.push(ds[i].name)
                            }
                        }
                    }

                    return nameArr.toString();
                },
                write: function(value){

                    this.setValue(fieldName, value)
                },
                owner: this
            })
        }
        Row.fn.refDate = function(fieldName,format){
            return ko.pureComputed({
                read: function(){
                    this.valueChange()
                    if(!this._getField(fieldName)['value']) return "";
                    var valArr = this._getField(fieldName)['value']
                    if(!valArr) return "";
                    valArr = moment(valArr).format(format)
                    return valArr;
                },
                write: function(value){

                    this.setValue(fieldName, value)
                },
                owner: this
            })
        }
        /**
         * 获取row中某一列的值
         */
        Row.fn.getValue = function(fieldName){
            return this._getField(fieldName)['value']
        }

        var eq = function(a, b) {
            if( (a === null || a === undefined || a === '') && (b === null || b === undefined || b === '')) return true;
            if($.isNumeric(a) && $.isNumeric(b) && parseFloat(a) == parseFloat(b) && (a+'').length==(b+'').length) return true;
            // add by songhlc 如果是重新设置数组则认为不一样
            if (a instanceof Array) return false
            if(a + '' == b + '')  return true;
            return false;
        }
        /**
         * 设置row中某一列的值
         */
        Row.fn.setValue = function(fieldName, value, ctx, options){
            var oldValue = this.getValue(fieldName) || ""
            if(eq(oldValue, value)) return ;
            this._getField(fieldName)['value'] = value
            this._getField(fieldName).changed = true
            if (this.status != Row.STATUS.NEW)
                this.status = Row.STATUS.UPDATE
            this.valueChange(- this.valueChange())
            if (this.parent.getCurrentRow() == this)
                this.parent.valueChange(- this.parent.valueChange());

            var event = {
                eventType:'dataTableEvent',
                dataTable:this.parent.id,
                rowId: this.rowId,
                field:fieldName,
                oldValue:oldValue,
                newValue:value,
                ctx: ctx || ""
            }
            this.parent.trigger(DataTable.ON_VALUE_CHANGE, event);
            this.parent.trigger(fieldName + "." + DataTable.ON_VALUE_CHANGE, event);
            if (this == this.parent.getCurrentRow())
                this.parent.trigger(fieldName + "." + DataTable.ON_CURRENT_VALUE_CHANGE, event);
        }

        /**
         * 获取row中某一列的属性
         */
        Row.fn.getMeta = function(fieldName, key, fetchParent){
            if (arguments.length == 0){
                var mt = {}
                for (var k in this.data){
                    mt[k] = this.data[k].meta ?  this.data[k].meta : {}
                }
                return mt
            }
            var meta = this._getField(fieldName).meta
            if (meta && meta[key] !== undefined && meta[key] !== null && meta[key] !== '' )
                return meta[key]
            else if (typeof fetchParent == 'undefined' || fetchParent != false)
                return this.parent.getMeta(fieldName, key)
            return undefined;
        }

        /**
         * 设置row中某一列的属性
         */
        Row.fn.setMeta = function(fieldName, key,value){
            var meta = this._getField(fieldName).meta
            if (!meta)
                meta = this._getField(fieldName).meta = {}
            var oldValue = meta[key]
            if(eq(oldValue, value)) return ;
            meta[key] = value
            // this.metaChange(- this.metaChange())
            if (this.metaChange[fieldName + '.' + key]) {
                this.metaChange[fieldName + '.' + key](-this.metaChange[fieldName + '.' + key]());
            }

            if (key == 'enable')
                this.parent.enableChange(- this.parent.enableChange())
            if (this.parent.getCurrentRow() == this){
                if (this.parent.metaChange[fieldName + '.' + key])
                    this.parent.metaChange[fieldName + '.' + key](- this.parent.metaChange[fieldName + '.' + key]());
                this.parent.trigger(fieldName + '.' + key + '.'+ DataTable.ON_CURRENT_META_CHANGE, {
                    eventType:'dataTableEvent',
                    dataTable:this.parent.id,
                    oldValue:oldValue,
                    newValue:value
                });
                // this.parent.metaChange(- this.parent.metaChange())
            }
            this.parent.trigger(DataTable.ON_ROW_META_CHANGE, {
                eventType:'dataTableEvent',
                dataTable:this.parent.id,
                field:fieldName,
                meta: key,
                oldValue:oldValue,
                newValue:value,
                row: this
            });

            this.parent.trigger(fieldName + '.' + key + '.' + DataTable.ON_ROW_META_CHANGE, {
                eventType:'dataTableEvent',
                dataTable:this.parent.id,
                field:fieldName,
                meta: key,
                oldValue:oldValue,
                newValue:value,
                row: this
            });
        }

        /**
         * 设置Row数据
         *
         * data.status data.data {'field1':
	 * {value:10,meta:{showValue:1.0,precision:2}}}
         */
        Row.fn.setData = function(data){
            this.status = data.status
            // this.rowId = data.rowId
            for(var key in data.data){
                if (this.data[key]){
                    var valueObj = data.data[key]
                    // modify by songhlc 添加boolean类型判断  juggle---
                    if (typeof valueObj == 'string' || typeof valueObj == 'number' || valueObj === null ||typeof valueObj == 'boolean')
                        this.data[key]['value'] = this.formatValue(key, valueObj)
                    // this.setValue(key, this.formatValue(key, valueObj))
                    // add by songhlc 添加数组判断 fixed
                    else if(valueObj  instanceof Array){
                        this.data[key]['value']= valueObj;
                    }
                    else{
// this.setValue(key, valueObj.value)

                        if(valueObj.error){
                            $.showMessageDialog({title:"警告",msg:valueObj.error,backdrop:true});
                        }else{
                            // this.setValue(key, this.formatValue(key,
                            // valueObj.value), null)
                            this.data[key]['value'] = this.formatValue(key, valueObj.value)
                            for(var k in valueObj.meta){
                                this.setMeta(key, k, valueObj.meta[k])
                            }
                        }
                    }
                }
            }
        }

        /**
         * 格式化数据值
         *
         * @private
         * @param {Object}
         *            field
         * @param {Object}
         *            value
         */
        Row.fn.formatValue = function(field, value){
            var type = this.parent.getMeta(field,'type')
            if (!type) return value
            // modify by songhlc 区分date和datetime
            if (type == 'date' ){
                return _formatDate(value)
            }
            else if(type == 'datetime'){
                return _formatDateTime(value)
            }
            return value
        }

        Row.fn.updateRow = function(row){
            this.setData(row)
        }

        /**
         * @private 提交数据到后台
         */
        Row.fn.getData = function(){
            var data = ko.toJS(this.data)
            var meta = this.parent.getMeta()
            for (var key in meta){
                if (meta[key] && meta[key].type){
                    if (meta[key].type == 'date' || meta[key].type == 'datetime'){
                        data[key].value = _dateToUTCString(data[key].value)
                    }
                }
            }
            return {'id':this.rowId ,'status': this.status, data: data}
        }

        Row.fn.getEmptyData = function(){
            return {'id':this.rowId ,'status': this.status, data: {}}
        }

        Row.fn._getField = function(fieldName){
            var rat = this.data[fieldName];
            if (!rat){
                throw new Error('field:' + fieldName + ' not exist in dataTable:' + this.parent.id +'!')
            }
            return rat
        }


        /*
	 * 生成随机行id @private
	 */
        Row.getRandomRowId = function() {
            return setTimeout(function(){}) + '';
        };

        var _formatDate = function(value){
            if (!value) return value
            var date = new Date(value);
            var year = date.getFullYear();
            var month = date.getMonth() + 1;
            if (parseInt(month)<10) month = "0" + month;
            var day = date.getDate();
            if (parseInt(day)<10) day = "0" + day;
            var formatString = year + "-" + month + "-" + day;
            return formatString;
        }
        // modify by songhlc 将formatDateTime和formatDate区分开来
        var _formatDateTime = function(value){
            if (!value) return value
            var date = new Date(value);
            var year = date.getFullYear();
            var month = date.getMonth() + 1;
            if (parseInt(month)<10) month = "0" + month;
            var day = date.getDate();
            if (parseInt(day)<10) day = "0" + day;
            var hours = date.getHours();
            if (parseInt(hours)<10) hours = "0" + hours;
            var minutes = date.getMinutes();
            if (parseInt(minutes)<10) minutes = "0" + minutes;
            var seconds = date.getSeconds();
            if (parseInt(seconds)<10) seconds = "0" + seconds;
            // modify by songhlc 去掉毫秒级的显示
            // var mill = date.getMilliseconds();
            var formatString = year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds ;// +
            // "."+mill;
            return formatString;
        }

        //yuncai modify by liangchen1
        var _dateToUTCString = function(date){
            if (!date) return null
            if (date.indexOf("-") > -1)
                date = date.replace(/\-/g,"/");
            var utcString = Date.parse(date);
            if (isNaN(utcString)) return null;
            return utcString;
        }

// if (exports){
        $.Row = Row
        $.DataTable = DataTable
// }
// else
// return {
// Row: Row,
// DataTable: DataTable
// }
//

    }($);

    +function($, ko) {

        "use strict";

        var CompManager = {
            plugs:{},
            apply : function(viewModel, dom){
                dom = dom || document.body
                $(dom).find('[u-meta]').each(function() {
                    if ($(this).data('u-meta')) return
                    if ($(this).parent('[u-meta]').length > 0) return
                    var options = JSON.parse($(this).attr('u-meta'))
                    if(options && options['type']) {
                        var comp = CompManager._createComp(this, options, viewModel, app)
// var comp = new DataComponent(this, options, viewModel)
                        if (comp)
                            $(this).data('u-meta', comp)
                    }
                })
                ko.applyBindings(viewModel, dom)
            },
            addPlug: function(plug){
                var name = plug.getName()
                this.plugs || (this.plugs = {})
                if (this.plugs[name]){
                    throw new Error('plug has exist:'+ name)
                }
                this.plugs[name] = plug
            },
            _createComp: function(element,options, viewModel, app){
                var type = options['type']
                var plug = this.plugs[type]
                if (!plug) return null
                var comp = new plug(element, options, viewModel, app)
                comp.type = type
                return comp
            }
        }

        $.compManager = CompManager


    }($,ko);


    +function($) {
        var FloatComp = $.InputComp.extend({
            initialize: function(element, options, viewModel) {
                var self = this
                FloatComp.superclass.initialize.apply(this, arguments)
                this.maskerMeta = iweb.Core.getMaskerMeta('float') || {}
                this.maskerMeta.precision = options['precision'] || this.maskerMeta.precision
                this.validType = 'float'
                this.max = options['max']?options['max']:"10000000000000000000"
                this.min = options['min']?options['min']:"-10000000000000000000"
                this.maxLength = options['maxLength']?options['maxLength']:25
                this.minLength = options['minLength']?options['minLength']:0
                this.maxNotEq = options['maxNotEq']
                this.minNotEq = options['minNotEq']

                if (this.dataModel) {
                    // 处理数据精度
                    if (this.hasDataTable) {
                        // this.dataModel.refRowMeta(this.field,
                        // "precision").subscribe(function(precision){
                        // if(precision === undefined)return;
                        // self.setPrecision(precision)
                        // })
                        this.dataModel.on(this.field + '.precision.' +  $.DataTable.ON_CURRENT_META_CHANGE, function(event){
                            if (event.newValue === undefined)
                                return;
                            self.setPrecision(event.newValue);
                        });

                        this.dataModel.on(this.field + '.precision.' +  $.DataTable.ON_ROW_META_CHANGE, function(event){
                            if (event.newValue === undefined)
                                return;
                            self.setPrecision(event.newValue);
                        })

                        this.maskerMeta.precision = this.dataModel.getMeta(this.field, "precision") || this.maskerMeta.precision
                        this.min =  $.isNumeric(this.dataModel.getMeta(this.field, "min")) ? this.dataModel.getMeta(this.field, "min") : this.min
                        this.max =  $.isNumeric(this.dataModel.getMeta(this.field, "max")) ? this.dataModel.getMeta(this.field, "max") : this.max
                        this.minLength = $.isNumeric(this.dataModel.getMeta(this.field, "minLength")) ? this.dataModel.getMeta(this.field, "minLength"):this.minLength
                        this.maxLength = $.isNumeric(this.dataModel.getMeta(this.field, "maxLength")) ? this.dataModel.getMeta(this.field, "maxLength"):this.maxLength
                        this.minNotEq = $.isNumeric(this.dataModel.getMeta(this.field, "minNotEq")) ? this.dataModel.getMeta(this.field, "minNotEq") : this.minNotEq
                        this.maxNotEq = $.isNumeric(this.dataModel.getMeta(this.field, "maxNotEq")) ?  this.dataModel.getMeta(this.field, "maxNotEq") : this.maxNotEq
                    }
                }
                this.formater = new $.NumberFormater(this.maskerMeta.precision);
                this.masker = new NumberMasker(this.maskerMeta);
                this.create()
            },
            modelValueChange: function(value) {
                if(value === null || typeof value == "undefined")
                    value = value || ""
                // this.trueValue = value
                // var formatValue = this.formater.format(this.trueValue)
                var pres = this.dataModel.getRowMeta(this.field, "precision");
                this.maskerMeta.precision = (pres === undefined || pres === null || pres === '') ? this.maskerMeta.precision : pres;
                this.formater.precision = this.maskerMeta.precision;
                var formatValue = this.formater.format(value)
                this.trueValue = formatValue
                this.element.trueValue = this.trueValue
                this.showValue = this.masker.format(formatValue).value
                this.setShowValue(this.showValue)
            },
            setValue: function(value) {
                this.maskerMeta.precision = this.dataModel.getRowMeta(this.field, "precision") || this.maskerMeta.precision
                this.formater.precision = this.maskerMeta.precision;
                var mvalue = this.dataModel.getCurrentRow().getValue(this.field)
                if(value == mvalue) {
                    this.showValue = this.masker.format(this.trueValue).value
                    this.setShowValue(this.showValue)
                } else {
                    this.trueValue = this.formater.format(value)
                    this.element.trueValue = this.trueValue
                    this.showValue = this.masker.format(this.trueValue).value
                    this.setShowValue(this.showValue)
                    this.setModelValue(this.trueValue)
                    this.trigger(FloatComp.EVENT_VALUE_CHANGE, this.trueValue)
                }

            },
            getValue : function() {
                return this.trueValue
            },
            setShowValue : function(showValue) {
                if(showValue !== null && showValue !== undefined ){
                    this.showValue = showValue
                    this.element.value = showValue
                    this.element.title = showValue
                }else{
                    this.showValue = ""
                }
            },
            getShowValue: function() {
                return this.showValue
            },
            /**
             * 修改精度
             *
             * @param {Integer}
             *            precision
             */
            setPrecision: function(precision){
                if (this.maskerMeta.precision == precision) return
                this.maskerMeta.precision =precision
                this.formater = new $.NumberFormater(this.maskerMeta.precision);
                this.masker = new NumberMasker(this.maskerMeta);
                var currentRow = this.dataModel.getCurrentRow();
                if(currentRow){
                    var v = this.dataModel.getCurrentRow().getValue(this.field)
                    this.showValue = this.masker.format(this.formater.format(v)).value
                }else{
                    this.showValue = this.masker.format(this.formater.format(this.trueValue)).value
                }

                this.setShowValue(this.showValue)
            },
            onFocusin: function(e) {
                var v = this.dataModel.getCurrentRow().getValue(this.field),vstr = v+'',focusValue = v
                if($.isNumeric(v) && $.isNumeric(this.maskerMeta.precision)) {
                    if(vstr.indexOf('.') >= 0) {
                        var sub = vstr.substr(vstr.indexOf('.')+1)
                        if(sub.length < this.maskerMeta.precision || parseInt(sub.substr(this.maskerMeta.precision)) == 0) {
                            focusValue = this.formater.format(v)
                        }
                    } else if(this.maskerMeta.precision > 0){
                        focusValue = this.formater.format(v)
                    }
                }
                this.setShowValue(focusValue)

            },
            _needClean: function(){
                return true
            },
            Statics: {
                compName: 'float'
            }
        })

        if ($.compManager)
            $.compManager.addPlug(FloatComp)

    }($);

    +function($){

        var Grid = function(element, options, viewModel,app) {
            // 初始options中包含grid的属性设置，还需要增加dataSource、columns、transMap以及事件处理
            var oThis = this;
            var compDiv = null;
            var comp = null;
            this.dataTable = $.getJSObject(viewModel, options["data"]);
            this.element = element;
            this.$element = $(element);
            this.editComponentDiv = {};
            this.editComponent = {};
            this.id = options['id'];
            this.gridOptions = options;

            // 在html中将函数类参数进行处理
            this.gridOptions.onBeforeRowSelected = $.getFunction(viewModel,this.gridOptions.onBeforeRowSelected);
            this.gridOptions.onRowSelected = $.getFunction(viewModel,this.gridOptions.onRowSelected);
            this.gridOptions.onBeforeRowUnSelected = $.getFunction(viewModel,this.gridOptions.onBeforeRowUnSelected);
            this.gridOptions.onRowUnSelected = $.getFunction(viewModel,this.gridOptions.onRowUnSelected);
            this.gridOptions.onBeforeAllRowSelected = $.getFunction(viewModel,this.gridOptions.onBeforeAllRowSelected);
            this.gridOptions.onAllRowSelected = $.getFunction(viewModel,this.gridOptions.onAllRowSelected);
            this.gridOptions.onBeforeAllRowUnSelected = $.getFunction(viewModel,this.gridOptions.onBeforeAllRowUnSelected);
            this.gridOptions.onAllRowUnSelected = $.getFunction(viewModel,this.gridOptions.onAllRowUnSelected);
            this.gridOptions.onBeforeRowFocus = $.getFunction(viewModel,this.gridOptions.onBeforeRowFocus);
            this.gridOptions.onRowFocus = $.getFunction(viewModel,this.gridOptions.onRowFocus);
            this.gridOptions.onBeforeRowUnFocus = $.getFunction(viewModel,this.gridOptions.onBeforeRowUnFocus);
            this.gridOptions.onRowUnFocus = $.getFunction(viewModel,this.gridOptions.onRowUnFocus);
            this.gridOptions.onDblClickFun = $.getFunction(viewModel,this.gridOptions.onDblClickFun);
            this.gridOptions.onValueChange = $.getFunction(viewModel,this.gridOptions.onValueChange);

            this.gridOptions.onBeforeRender = $.getFunction(viewModel,this.gridOptions.onBeforeRender);
            this.gridOptions.onRowHover = $.getFunction(viewModel,this.gridOptions.onRowHover);
            this.gridOptions.onRowUnHover = $.getFunction(viewModel,this.gridOptions.onRowUnHover);

            /*
		 * 处理column参数 item div子项div存储column信息
		 */
            var columns = [];
            $("div",this.$element).each(function() {
                var ops = $(this).attr('options')
                if(typeof(ops) == "undefined")
                    var column = eval("(" + ops+")");
                else
                    var column = JSON.parse(ops);
                // 处理精度，以dataTable的精度为准

                /* 处理editType */
                var eType = $.getFunction(viewModel, column.editType);
                var rType = $.getFunction(viewModel, column.renderType);
                var sumRenderType = $.getFunction(viewModel, column.sumRenderType);
                column.sumRenderType = sumRenderType;
                // add by songhlc 添加autocomplete组件
                var autoType = $.getFunction(viewModel, column.autoType);
                var eOptions;
                if(column.editOptions){
                    if(typeof(column.editOptions) == "undefined")
                        eOptions = eval("(" + column.editOptions +")");
                    else
                        eOptions = column.editOptions;
                } else {
                    eOptions = column.editOptions = {};
                }
                eOptions.data = options['data']
                eOptions.field = column['field']
                // 默认按照string处理
                if(eType == '')
                    eType = 'string';
                // add by songhlc 添加autocomplete类型
                if(eType == 'string' || eType == 'integer' || eType == 'checkbox' || eType == 'combo' || eType == 'radio' || eType == 'float' || eType == 'currency' || eType == 'datetime'|| eType == 'date' || eType == 'time'|| eType =='autocomplete'){
                    if(eType == 'string'){
                        compDiv = $('<div><input type="text" class="u-grid-edit-item-string"></div>');
                        if(!options.editType || options.editType =="default" ){
                            compDiv.addClass("eType-input")
                        }
                        comp = new $.compManager.plugs.string(compDiv.find("input")[0],eOptions,viewModel);

                    }else if(eType == 'integer'){
                        compDiv = $('<div><input type="text" class="u-grid-edit-item-integer"></div>');
                        if(!options.editType || options.editType =="default" ){
                            compDiv.addClass("eType-input")
                        }
                        comp = new $.compManager.plugs.integer(compDiv.find("input")[0],eOptions,viewModel);

                    } else if(eType == 'checkbox'){
                        compDiv = $('<div><input id="' + oThis.id + "_edit_field_" + column['field'] + '" type="checkbox" class="u-grid-edit-item-checkbox"></div>');
                        comp = new $.compManager.plugs.check(compDiv.find("input")[0],eOptions,viewModel);

                    }else if(eType == 'combo'){
                        compDiv = $('<div class="input-group  form_date u-grid-edit-item-comb"><div  type="text" class="form-control grid-combox"></div><i class="input-group-addon" ><i class="fa fa-angle-down"></i></i></div>');
                        comp = new $.compManager.plugs.combo(compDiv[0],eOptions,viewModel);

                    }else if(eType == 'radio'){
                        if(!options.editType || options.editType =="default" ){
                            compDiv = null;
                            comp = null;
                        }else {
                            compDiv = $('<div class="u-grid-edit-item-radio"><input type="radio" name="identity" /><i data-role="name"></i></div>');
                            comp = new $.compManager.plugs.radio(compDiv[0],eOptions,viewModel);
                        }
                    }else if(eType == 'float'){
                        compDiv = $('<div><input type="text" class="u-grid-edit-item-float"></div>');
                        if(!options.editType || options.editType =="default" ){
                            compDiv.addClass("eType-input")
                        }
                        comp = new $.compManager.plugs.float(compDiv.find("input")[0],eOptions,viewModel);
                    }else if(eType == 'currency'){
                        compDiv = $('<div><input type="text" class="u-grid-edit-item-currency"></div>');
                        if(!options.editType || options.editType =="default" ){
                            compDiv.addClass("eType-input")
                        }
                        comp = new $.compManager.plugs.currency(compDiv.find("input")[0],eOptions,viewModel);
                    }else if(eType == 'datetime'){
                        compDiv = $('<div class="input-group u-grid-edit-item-datetime" ><input class="form-control" /><div class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></div></div>');

                        comp = new $.compManager.plugs.datetime(compDiv[0],eOptions,viewModel);
                    }else if(eType == 'date'){
                        compDiv = $('<div class="input-group u-grid-edit-item-date" ><input class="form-control" /><div class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></div></div>');

                        comp = new $.compManager.plugs.date(compDiv[0],eOptions,viewModel);
                    }else if(eType == 'time'){
                        compDiv = $('<div class="input-group u-grid-edit-item-date" ><input class="form-control" /><div class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></div></div>');

                        comp = new $.compManager.plugs.time(compDiv[0],eOptions,viewModel);
                    }// add by songhlc 添加 autocomplete控件
                    else if(eType == 'autocomplete'){
                        compDiv = $('<div><input type="text" class="u-grid-edit-item-string"></div>');
                        if(!options.editType || options.editType =="default" ){
                            compDiv.addClass("eType-input")
                        }
                        eOptions.autoType = autoType;
                        comp = new $.compManager.plugs.autocomplete(compDiv.find("input")[0],eOptions,viewModel);

                    }

                    oThis.editComponentDiv[column.field] = compDiv;
                    oThis.editComponent[column.field] = comp;


                    column.editType = function(obj){
                        if(oThis.editComponentDiv[column.field][0].childNodes.length > 0){
                        }else{
                            // IE8有问题，所以需要重新创建div,将上面的代码直接拷贝
                            if(eType == 'string'){
                                compDiv = $('<div><input type="text" class="u-grid-edit-item-string"></div>');
                                if(!options.editType || options.editType =="default" ){
                                    compDiv.addClass("eType-input")
                                }
                                comp = new $.compManager.plugs.string(compDiv.find("input")[0],eOptions,viewModel);

                            }else if(eType == 'integer'){
                                compDiv = $('<div><input type="text" class="u-grid-edit-item-integer"></div>');
                                if(!options.editType || options.editType =="default" ){
                                    compDiv.addClass("eType-input")
                                }
                                comp = new $.compManager.plugs.integer(compDiv.find("input")[0],eOptions,viewModel);

                            } else if(eType == 'checkbox'){
                                compDiv = $('<div><input id="' + oThis.id + "_edit_field_" + column['field'] + '" type="checkbox" class="u-grid-edit-item-checkbox"></div>');
                                comp = new $.compManager.plugs.check(compDiv.find("input")[0],eOptions,viewModel);

                            }else if(eType == 'combo'){
                                compDiv = $('<div class="input-group  form_date u-grid-edit-item-comb"><div  type="text" class="form-control grid-combox"></div><i class="input-group-addon" ><i class="fa fa-angle-down"></i></i></div>');
                                comp = new $.compManager.plugs.combo(compDiv[0],eOptions,viewModel);

                            }else if(eType == 'radio'){
                                if(!options.editType || options.editType =="default" ){
                                    compDiv = null;
                                    comp = null;
                                }else {
                                    compDiv = $('<div class="u-grid-edit-item-radio"><input type="radio" name="identity" /><i data-role="name"></i></div>');
                                    comp = new $.compManager.plugs.radio(compDiv[0],eOptions,viewModel);
                                }
                            }else if(eType == 'float'){
                                compDiv = $('<div><input type="text" class="u-grid-edit-item-float"></div>');
                                if(!options.editType || options.editType =="default" ){
                                    compDiv.addClass("eType-input")
                                }
                                comp = new $.compManager.plugs.float(compDiv.find("input")[0],eOptions,viewModel);
                            }else if(eType == 'currency'){
                                compDiv = $('<div><input type="text" class="u-grid-edit-item-currency"></div>');
                                if(!options.editType || options.editType =="default" ){
                                    compDiv.addClass("eType-input")
                                }
                                comp = new $.compManager.plugs.currency(compDiv.find("input")[0],eOptions,viewModel);
                            }else if(eType == 'datetime'){
                                compDiv = $('<div class="input-group u-grid-edit-item-datetime" ><input class="form-control" /><div class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></div></div>');
                                eOptions.widgetParent = $("body")
                                comp = new $.compManager.plugs.datetime(compDiv[0],eOptions,viewModel);
                            }else if(eType == 'date'){
                                compDiv = $('<div class="input-group u-grid-edit-item-date" ><input class="form-control" /><div class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></div></div>');
                                eOptions.widgetParent = $("body")
                                comp = new $.compManager.plugs.date(compDiv[0],eOptions,viewModel);
                            }else if(eType == 'time'){
                                compDiv = $('<div class="input-group u-grid-edit-item-date" ><input class="form-control" /><div class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></div></div>');
                                eOptions.widgetParent = $("body")
                                comp = new $.compManager.plugs.time(compDiv[0],eOptions,viewModel);
                            }

                            oThis.editComponentDiv[column.field] = compDiv;
                            oThis.editComponent[column.field] = comp;
                        }

                        var comp = oThis.editComponent[column.field]
                        if (!comp)
                            return
                        obj.element.innerHTML = '';
                        var $Div = $('<div class="u-grid-content-td-div" style="margin:0px;"></div>');
                        var row = oThis.getDataTableRow(obj.rowObj)
                        $(obj.element).append($Div);
                        $Div.append(oThis.editComponentDiv[column.field]);
                        if(comp.required) {
                            $(obj.element).parent().find('.u-grid-edit-mustFlag').show()
                        }

                        // checkbox 类型
                        if($Div.find('.checkbox').length > 0) {
                            $Div.closest('.u-grid-edit-div').css({'position': 'absolute', 'left': '83px'});
                            $Div.closest('.u-grid-edit-whole-div').find('.u-grid-edit-label').css({'margin-left': '124px', 'text-align': 'left'})
                        }
                        comp.modelValueChange(obj.value);
                    }
                }else if (typeof eType == 'function'){
                    column.editType = eType;
                }

                if(rType == 'booleanRender'){
                    column.renderType = function(obj){
                        var checkStr = '';
                        if(obj.value == 'Y'){
                            checkStr = 'checked';
                        }
                        var htmlStr = '<input type="checkbox"   style="cursor:default;" disabled ' + checkStr +'>'
                        obj.element.innerHTML = htmlStr;
                    }
                }else if(rType == 'integerRender'){
                    column.renderType = function(obj){
                        obj.element.innerHTML =  obj.value
                        $(obj.element).css('text-align', 'right')
                    }
                }else if(rType == 'currencyRender'){
                    column.renderType = function(obj){
                        // 需要处理精度

                        var grid = obj.gridObj
                        var column = obj.gridCompColumn
                        var field = column.options.field
                        var rowIndex = obj.rowIndex
                        var datatable = grid.dataTable
                        var rowId =  $(grid.dataSourceObj.rows[rowIndex].value).attr("$_#_@_id");
                        var row = datatable.getRowByRowId(rowId);

                        var rprec = row.getMeta(field, 'precision')
                        var maskerMeta = iweb.Core.getMaskerMeta('float') || {}
                        var precision = typeof(parseFloat(rprec)) == 'number' ? rprec : maskerMeta.precision;
                        maskerMeta.precision = precision;

                        maskerMeta.precision = precision || maskerMeta.precision
                        var formater = new $.NumberFormater(maskerMeta.precision);
                        var masker = new NumberMasker(maskerMeta);
                        var svalue = masker.format(formater.format(obj.value)).value
                        obj.element.innerHTML =  svalue
                        $(obj.element).css('text-align', 'right')
                        $(obj.element).attr('title', svalue)
                    }
                }else if(rType == 'floatRender'){
                    column.renderType = function(obj){
                        // 需要处理精度

                        var grid = obj.gridObj
                        var column = obj.gridCompColumn
                        var field = column.options.field
                        var rowIndex = obj.rowIndex
                        var datatable = grid.dataTable
                        var rowId =  $(grid.dataSourceObj.rows[rowIndex].value).attr("$_#_@_id");
                        var row = datatable.getRowByRowId(rowId);

                        var rprec = row.getMeta(field, 'precision')
                        var maskerMeta = iweb.Core.getMaskerMeta('float') || {}
                        var precision = typeof(parseFloat(rprec)) == 'number' ? rprec : maskerMeta.precision;
                        maskerMeta.precision = precision;

                        var formater = new $.NumberFormater(maskerMeta.precision);
                        var masker = new NumberMasker(maskerMeta);
                        var svalue = masker.format(formater.format(obj.value)).value
                        obj.element.innerHTML =  svalue
                        $(obj.element).css('text-align', 'right')
                        $(obj.element).attr('title', svalue)
                    }
                }else if(rType == 'comboRender'){
                    column.renderType = function(obj){

                        // 需要将key转化为name
                        var ds = $.getJSObject(viewModel, eOptions['datasource'])

                        obj.element.innerHTML = '';
                        if(nameArr){
                            nameArr.length = 0
                        }

                        var valArr = obj.value.split(',')
                        var nameArr = []
                        for( var i=0,length=ds.length; i<length; i++){
                            for(var j=0; j<valArr.length;j++){
                                if(ds[i].pk == valArr[j]){
                                    nameArr.push(ds[i].name)
                                }
                            }
                        }
                        var svalue = nameArr.toString()
                        obj.element.innerHTML = svalue;
                        $(obj.element).attr('title', svalue)

                    }
                }else if(rType == 'dateRender'){
                    // 通过grid的dataType为Date format处理
                    column.renderType = function(obj){
                        var svalue =  moment(obj.value).format('YYYY-M-D ') // $.dateRender(obj.value)
                        obj.element.innerHTML = svalue;
                        $(obj.element).attr('title', svalue)
                    }
                }else if(rType == 'dateTimeRender'){
                    // 通过grid的dataType为DateTime format处理
                    column.renderType = function(obj){
                        var svalue = moment(obj.value).format('YYYY-M-D HH:mm'); // $.dateTimeRender(obj.value)
                        obj.element.innerHTML = svalue;
                        $(obj.element).attr('title', svalue)
                    }
                }else if (typeof rType == 'function'){
                    column.renderType =  rType
                }else if(rType == 'radioRender'){
                    column.renderType = function(params){
                        // debugger
                        var ds = $.getJSObject(viewModel, eOptions['datasource'])
                        var value = params.value
                        var compDiv = $('<div class="u-grid-edit-item-radio"></div>');

                        params.element.innerHTML = ""
                        $(params.element).append(compDiv)

                        for(var i = 0;i < ds.length;i++){
                            if(ds[i].pk==value)
                                compDiv.append('<input name="'+column.field+params.row.value['$_#_@_id']+'" type="radio" value="'+ds[i].pk +'" checked="true" /><i data-role="name">' +ds[i].name+ '</i>')
                            else
                                compDiv.append('<input name="'+column.field+params.row.value['$_#_@_id']+'" type="radio" value="'+ds[i].pk +'"/><i data-role="name">' +ds[i].name+ '</i>')
                        }
                        compDiv.find(":radio").each(function() {

                            $(this).on('click', function() {

                                var val = this.value
                                compDiv.find(":radio").each(function() {
                                    if (this.value == val) {
                                        this.checked = true;
                                    }else{
                                        this.checked = false;
                                    }
                                })
                                var grid = params.gridObj
                                var column = params.gridCompColumn
                                var field = column.options.field
                                var datatable = grid.dataTable
                                // var rowIndex = params.rowIndex
                                // var tmprowId =
                                // $(grid.dataSourceObj.rows[rowIndex].value).attr("$_#_@_id");
                                var rowId = params.row.value['$_#_@_id'];

                                var row = datatable.getRowByRowId(rowId);

                                row.setValue(field,val)
                            })
                        })
// var comp = new $.compManager.plugs.radio(compDiv[0],eOptions,viewModel);
// for( var i=0,length=rdo.length; i<length; i++){
// if(rdo[i].pk==value){
// obj.element.innerHTML = '<input type="radio" checked><i
// data-role="name">'+rdo[i].name+'</i>';
// break;
// }
// }

                    }
                }
                columns.push(column);
            });

            if (app && app.adjustFunc)
                app.adjustFunc.call(app, {id: this.id, type:'gridColumn', columns:columns});

            this.gridOptions.columns = columns;


            /*
		 * 处理viewModel与grid之间的绑定
		 *
		 */
            var onRowSelectedFun = this.gridOptions.onRowSelected;
            // 选中
            this.gridOptions.onRowSelected = function(obj) {
                var rowId = oThis.grid.dataSourceObj.rows[obj.rowIndex].value['$_#_@_id'];
                var index = oThis.dataTable.getIndexByRowId(rowId);
                if(oThis.grid.options.multiSelect){
                    oThis.dataTable.addRowsSelect([index]);
                }else{
                    oThis.dataTable.setRowSelect(index);
                }

                if(onRowSelectedFun){
                    onRowSelectedFun.call(oThis,obj);
                }
            };
            this.dataTable.on($.DataTable.ON_ROW_SELECT, function(event) {
                /* index转化为grid的index */
                $.each(event.rowIds, function() {
                    var index = oThis.grid.getRowIndexByValue('$_#_@_id',this);
                    var selectFlag = true;
                    if(index > -1){
                        selectFlag = oThis.grid.setRowSelect(parseInt(index));
                        if(!selectFlag){
                            oThis.dataTable.setRowUnSelect(oThis.dataTable.getIndexByRowId(this));
                        }
                    }
                });
            });

            // 全选
            this.dataTable.on($.DataTable.ON_ROW_ALLSELECT, function(event) {
                oThis.grid.setAllRowSelect()
            });

            // 全返选
            this.dataTable.on($.DataTable.ON_ROW_ALLUNSELECT, function(event) {
                oThis.grid.setAllRowUnSelect()
            });

            // 反选
            var onRowUnSelectedFun = this.gridOptions.onRowUnSelected;
            this.gridOptions.onRowUnSelected = function(obj) {
                var rowId = oThis.grid.dataSourceObj.rows[obj.rowIndex].value['$_#_@_id'];
                var index = oThis.dataTable.getIndexByRowId(rowId);
                oThis.dataTable.setRowUnSelect(index);
                if(onRowUnSelectedFun){
                    onRowUnSelectedFun.call(oThis,obj);
                }
            };
            this.dataTable.on($.DataTable.ON_ROW_UNSELECT, function(event) {
                $.each(event.rowIds, function() {
                    var index = oThis.grid.getRowIndexByValue('$_#_@_id',this);
                    var unSelectFlag = true;
                    if(index > -1){
                        unSelectFlag = oThis.grid.setRowUnselect(parseInt(index));
                        if(!unSelectFlag){
                            if(oThis.grid.options.multiSelect){
                                oThis.dataTable.addRowsSelect([oThis.dataTable.getIndexByRowId(this)]);
                            }else{
                                oThis.dataTable.setRowSelect(oThis.dataTable.getIndexByRowId(this));
                            }
                        }
                    }
                });
            });

            var onRowFocusFun = this.gridOptions.onRowFocus;
            // focus
            this.gridOptions.onRowFocus = function(obj) {
                var rowId = oThis.grid.dataSourceObj.rows[obj.rowIndex].value['$_#_@_id'];
                var index = oThis.dataTable.getIndexByRowId(rowId);

                if(oThis.grid.options.rowClickBan) {
                    oThis.dataTable.setRowFocus(index, true);
                } else {
                    oThis.dataTable.setRowFocus(index);
                }

                if(onRowFocusFun){
                    onRowFocusFun.call(oThis,obj);
                }
            };
            this.dataTable.on($.DataTable.ON_ROW_FOCUS, function(event) {
                /* index转化为grid的index */
                var index = oThis.grid.getRowIndexByValue('$_#_@_id',event.rowId);

                var focusFlag = true;
                if(index > -1){
                    focusFlag = oThis.grid.setRowFocus(parseInt(index));

                    if(!focusFlag){
                        oThis.dataTable.setRowUnFocus(oThis.dataTable.getIndexByRowId(event.rowId));
                    }
                }
            });

            // 反focus
            var onRowUnFocusFun = this.gridOptions.onRowUnFocus;
            this.gridOptions.onRowUnFocus = function(obj) {
                var rowId = oThis.grid.dataSourceObj.rows[obj.rowIndex].value['$_#_@_id'];
                var index = oThis.dataTable.getIndexByRowId(rowId);
                oThis.dataTable.setRowUnFocus(index);
                if(onRowUnFocusFun){
                    onRowUnFocusFun.call(oThis,obj);
                }
            };
            this.dataTable.on($.DataTable.ON_ROW_UNFOCUS, function(event) {
                var index = oThis.grid.getRowIndexByValue('$_#_@_id',event.rowId);
                var unFocusFlag = true;
                if(index > -1){
                    unFocusFlag = oThis.grid.setRowUnFocus(parseInt(index));
                    if(!unFocusFlag){
                        oThis.dataTable.setRowFocus(oThis.dataTable.getIndexByRowId(event.rowId));
                    }
                }
            });

            // 增行,只考虑viewModel传入grid
// var onRowInsertFun = this.gridOptions.onRowInsert;
// this.gridOptions.onRowInsert = function(obj){
// dataTable.insertRow(obj.index,obj.row);
// if(onRowSelectedFun){
// viewModel[onRowUnSelectedFun].call(grid,grid, row, rowindex);
// }
// };
            this.dataTable.on($.DataTable.ON_INSERT, function(event) {
                var gridRows = new Array();
                $.each(event.rows,function(){
                    var row = this.data;
                    var id = this.rowId;
                    var gridRow = {};
                    for(var filed in row){
                        gridRow[filed] = row[filed].value;
                    }
                    gridRow['$_#_@_id'] = id;
                    gridRows.push(gridRow);
                })
                oThis.grid.addRows(gridRows,event.index);
            });

            this.dataTable.on($.DataTable.ON_UPDATE, function(event) {
                $.each(event.rows,function(){
                    var row = this.data;
                    var id = this.rowId;
                    var gridRow = {};
                    for(var filed in row){
                        gridRow[filed] = row[filed].value;
                    }
                    gridRow['$_#_@_id'] = id;
                    var index = oThis.grid.getRowIndexByValue('$_#_@_id',id);
                    oThis.grid.updateRow(index,gridRow);
                })

            });

            this.dataTable.on($.DataTable.ON_VALUE_CHANGE, function(obj) {

                var id = obj.rowId;
                var index = oThis.grid.getRowIndexByValue('$_#_@_id',id);
                if(index == -1) {
                    return;
                }
                var field = obj.field;
                var value = obj.newValue;
                oThis.grid.updateValueAt(index,field,value);

            });

            // 删除行,只考虑viewModel传入grid
// this.gridOptions.onRowDelete = function(obj){
// dataTable.removeRow(obj.index);
// };
            this.dataTable.on($.DataTable.ON_DELETE, function(event) {
                /* index转化为grid的index */
                var gridIndexs = new Array();
                $.each(event.rowIds, function() {
                    var index = oThis.grid.getRowIndexByValue('$_#_@_id',this);
                    gridIndexs.push(index);
                });
                oThis.grid.deleteRows(gridIndexs);
            });

            this.dataTable.on($.DataTable.ON_DELETE_ALL, function(event) {
                oThis.grid.setDataSource({})
            });

            // 数据改变
            var onValueChangeFun = this.gridOptions.onValueChange;
            this.gridOptions.onValueChange = function(obj) {
                var row = oThis.getDataTableRow(oThis.grid.dataSourceObj.rows[obj.rowIndex].value)
                if(row){
                    if($.type(obj.newValue) == 'object') {
                        row.setValue(obj.field, obj.newValue.trueValue);
                        row.setMeta(obj.field, 'display', obj.newValue.showValue);
                    } else {
                        row.setValue(obj.field,obj.newValue);
                    }
                }
                if(onValueChangeFun){
                    onValueChangeFun.call(oThis,obj);
                }
            };
            this.dataTable.on('valueChange', function(event) {
                var field = event.field,
                    rowId = event.rowId,
                    oldValue = event.oldValue,
                    newValue = event.newValue;
                var rowIndex = oThis.grid.getRowIndexByValue('$_#_@_id',rowId);
                if(rowIndex > -1){
                    oThis.grid.updateValueAt(rowIndex,field,newValue);
                }
            });
            // 加载数据,只考虑viewModel传入grid
            this.dataTable.on($.DataTable.ON_LOAD, function(data) {
                if(data.length > 0){
                    var values = new Array();

                    $.each(data, function() {
                        var value = {};
                        var dataObj = this.data;
                        var id = this.rowId;
                        for(var p in dataObj){
                            //var v = dataObj[p].value;
                            var v = dataObj[p];
                            value[p] = v;
                        }
                        value['$_#_@_id'] = id;
                        values.push(value);
                    });
                    var dataSource = {};
                    dataSource['values'] = values;
                    oThis.grid.setDataSource(dataSource);
                }
            });
            this.dataTable.on($.DataTable.ON_ENABLE_CHANGE, function(enable) {
                oThis.grid.setEditable(enable.enable);
            });

            this.dataTable.on($.DataTable.ON_ROW_META_CHANGE, function(event){
                var field = event.field,
                    meta = event.meta,
                    row = event.row,
                    newValue = event.newValue
                if (meta == 'required'){
                    oThis.grid.setRequired(field, newValue)
                }
                if (meta == 'precision'){
                    var comp = oThis.editComponent[field];
                    if(comp) {
                        comp.setPrecision(newValue)
                    }

                    var index = oThis.grid.getRowIndexByValue('$_#_@_id',row.rowId);
                    if(index == -1) {
                        return;
                    }
                    var value = row.getValue(field)

                    oThis.grid.updateValueAt(index,field,value,true);
                }
            })

            this.dataTable.on($.DataTable.ON_META_CHANGE, function(event){
                var field = event.field
                var meta = event.meta
                if (meta == 'precision'){
                    oThis.grid.renderTypeFun({field:field})
                }
            })

            var onRowHoverFun = this.gridOptions.onRowHover;
            // hover
            this.gridOptions.onRowHover = function(obj) {
                var rowId = oThis.grid.dataSourceObj.rows[obj.rowIndex].value['$_#_@_id'];
                var index = oThis.dataTable.getIndexByRowId(rowId);

                oThis.dataTable.setRowHover(index);

                if(onRowHoverFun){
                    onRowHoverFun.call(oThis,obj);
                }
            };

            var onRowUnHoverFun = this.gridOptions.onRowUnHover;
            this.gridOptions.onRowUnHover = function(obj) {
                var rowId = oThis.grid.dataSourceObj.rows[obj.rowIndex].value['$_#_@_id'];
                var index = oThis.dataTable.getIndexByRowId(rowId);

                oThis.dataTable.setRowUnHover();

                if(onRowUnHoverFun){
                    onRowUnHoverFun.call(oThis,obj);
                }
            };


            // 创建grid
            this.grid = $(element).grid(this.gridOptions);
            this.grid.dataTable = this.dataTable
            this.grid.viewModel = viewModel
            this.grid.gridModel = this



            // 如果先插入数据再创建grid需要处理 load
            var data = this.dataTable.rows();
            if(data.length > 0){
                var values = new Array();

                $.each(data, function() {
                    var value = {};
                    var dataObj = this.data;
                    var id = this.rowId;
                    for(var p in dataObj){
                        var v = dataObj[p].value;
                        value[p] = v;
                    }
                    value['$_#_@_id'] = id;
                    values.push(value);
                });
                var dataSource = {};
                dataSource['values'] = values;
                oThis.grid.setDataSource(dataSource);
            }
            // 选中行
            var selectIndexs = this.dataTable.getSelectedIndexs();
            if(selectIndexs.length > 0){
                $.each(selectIndexs, function() {
                    oThis.grid.setRowSelect(this);
                });
            }

            return this;
        }

        Grid.getName = function() {
            return 'grid'
        }

        Grid.fn = Grid.prototype

        /**
         * 获取grid行对应的数据模型行对象
         *
         * @param {Object}
         *            gridRow
         */
        Grid.fn.getDataTableRow = function(gridRow){
            var rowId =  gridRow['$_#_@_id']
            var row = null
            var rowIndex = this.dataTable.getIndexByRowId(rowId)
            if(rowIndex > -1)
                row = this.dataTable.getRow(rowIndex);
            return row
        }

        Grid.fn.setEnable = function(enable){
            this.grid.setEditable(enable);
        }

        Grid.fn.setShowHeader = function(showHeader){
            this.grid.setShowHeader(showHeader);
        }

        // 传入要编辑的tr对应的jquery对象
        Grid.fn.editRowFun = function(index){
            this.dataTable.setRowSelect(index);
            this.grid.editRowIndexFun(index);
        }

        if ($.compManager)
            $.compManager.addPlug(Grid)

    }($);

    + function($) {

        var Tree = function(element, options, viewModel) {
            var oThis = this;
            this.dataTable = $.getJSObject(viewModel, options["data"]);
            this.element = element;
            this.$element = $(element);
            this.id = options['id'];
            this.element.id = this.id;
            this.options = options;
            this.events = $.extend(true, {}, options.events);
            var treeSettingDefault = {
                // async: { //缓加载
                // enable: oThis.options.asyncFlag,
                // url: oThis.options.asyncFun
                // },
                data: {
                    simpleData: {
                        enable: true
                    }
                },
                check: {
                    chkboxType: {
                        "Y": "",
                        "N": ""
                    }
                },
                callback: {
                    // 点击前
                    beforeClick: function(e, id, node) {
                        if (oThis.events.beforeClick) {
                            $.getFunction(viewModel, oThis.events.beforeClick)(e, id, node);
                        }
                    },
                    // 选中/取消选中事件
                    onCheck: function(e, id, node) {
                        // 获取到节点的idValue
                        var idValue = node.id;
                        // 根据idValue查找到对应数据的rowId
                        var rowId = oThis.getRowIdByIdValue(idValue);
                        var index = oThis.dataTable.getIndexByRowId(rowId);
                        if (node.checked) {
                            // 选中数据行
                            if (oThis.tree.setting.view.selectedMulti == true) {
                                oThis.dataTable.addRowsSelect([index]);
                            } else {
                                oThis.dataTable.setRowSelect(index);
                            }
                        } else {
                            oThis.dataTable.setRowUnSelect(index);
                        }

                    },
                    // 单选时点击触发选中
                    onClick: function(e, id, node) {
                        if (oThis.tree.setting.view.selectedMulti != true) {
                            // 获取到节点的idValue
                            var idValue = node.id;
                            // 根据idValue查找到对应数据的rowId
                            var rowId = oThis.getRowIdByIdValue(idValue);
                            var index = oThis.dataTable.getIndexByRowId(rowId);
                            oThis.dataTable.setRowSelect(index);
                            if (oThis.events.onClick) {
                                $.getFunction(viewModel, oThis.events.onClick)(e, id, node);
                            }
                        }

                    }
                }

            };

            var setting = {};
            if (this.options.setting) {
                // if (typeof(JSON) == "undefined")
                // setting = eval("(" + this.options.setting + ")");
                // else
                setting = $.getJSObject(viewModel, this.options.setting) || $.getJSObject(window, this.options.setting);
            }
            var treeSetting = $.extend({}, treeSettingDefault, setting);

            var treeData = [];
            // 根据idField、pidField、nameField构建ztree所需data
            var data = this.dataTable.rows();
            if (data.length > 0) {
                if (this.options.codeTree) {
                    // 首先按照string进行排序
                    data.sort(function(a, b) {
                        var aObj = a.data;
                        var bObj = b.data;
                        var v1 = aObj[oThis.options.idField].value + '';
                        var v2 = bObj[oThis.options.idField].value + '';
                        try {
                            return v1.localeCompare(v2);
                        } catch (e) {
                            return 0;
                        }
                    });
                    var idArr = new Array();
                    $.each(data, function() {
                        var dataObj = this.data;
                        var idValue = dataObj[oThis.options.idField].value;
                        idArr.push(idValue);
                    });
                    var preValue = '';
                    $.each(data, function() {
                        var value = {};
                        var dataObj = this.data;
                        var idValue = dataObj[oThis.options.idField].value;
                        var nameValue = dataObj[oThis.options.nameField].value;
                        var pidValue = '';
                        var startFlag = -1;
                        // 如果当前值包含上一个值则上一个值为pid
                        if (preValue != '') {
                            var startFlag = idValue.indexOf(preValue);
                        }
                        if (startFlag == 0) {
                            pidValue = preValue;
                        } else {
                            for (var i = 1; i < preValue.length; i++) {
                                var s = preValue.substr(0, i);
                                var f = idValue.indexOf(s);
                                if (f == 0) {
                                    var index = $.inArray(s, idArr);
                                    if (index > 0 || index == 0) {
                                        pidValue = s;
                                    }
                                } else {
                                    break;
                                }
                            }

                        }
                        value['id'] = idValue;
                        value['pId'] = pidValue;
                        value['name'] = nameValue;

                        treeData.push(value);
                        preValue = idValue;
                    });
                } else {
                    var values = new Array();
                    $.each(data, function() {
                        var value = {};
                        var dataObj = this.data;
                        var idValue = dataObj[oThis.options.idField].value;
                        var pidValue = dataObj[oThis.options.pidField].value;
                        var nameValue = dataObj[oThis.options.nameField].value;

                        value['id'] = idValue;
                        value['pId'] = pidValue;
                        value['name'] = nameValue;
                        treeData.push(value);
                    });
                }
            }

            this.tree = $.fn.zTree.init(this.$element, treeSetting, treeData);


            // dataTable事件
            this.dataTable.on($.DataTable.ON_ROW_SELECT, function(event) {
                /* index转化为grid的index */
                $.each(event.rowIds, function() {
                    var row = oThis.dataTable.getRowByRowId(this);
                    var dataObj = row.data;
                    var idValue = dataObj[oThis.options.idField].value;
                    var node = oThis.tree.getNodeByParam('id', idValue);
                    if (oThis.tree.setting.view.selectedMulti == true  && !node.checked) {
                        oThis.tree.checkNode(node);
                    } else {
                        oThis.tree.selectNode(node, false);
                    }
                });
            });

            this.dataTable.on($.DataTable.ON_ROW_UNSELECT, function(event) {
                /* index转化为grid的index */
                $.each(event.rowIds, function() {
                    var row = oThis.dataTable.getRowByRowId(this);
                    var dataObj = row.data;
                    var idValue = dataObj[oThis.options.idField].value;
                    var node = oThis.tree.getNodeByParam('id', idValue);
                    if (oThis.tree.setting.view.selectedMulti == true && node.checked) {
                        oThis.tree.checkNode(node);
                    } else {
                        oThis.tree.cancelSelectedNode(node)
                    }
                });
            });

            this.dataTable.on($.DataTable.ON_INSERT, function(event) {
                var gridRows = new Array();
                $.each(event.rows, function() {
                    var value = {};
                    var dataObj = this.data;
                    var idValue = dataObj[oThis.options.idField].value;
                    var pidValue = dataObj[oThis.options.pidField].value;
                    var nameValue = dataObj[oThis.options.nameField].value;

                    value['id'] = idValue;
                    value['pId'] = pidValue;
                    value['name'] = nameValue;
                    var pNode = oThis.tree.getNodeByParam('id', pidValue);
                    oThis.tree.addNodes(pNode, value, true);
                })
            });

            this.dataTable.on($.DataTable.ON_DELETE, function(event) {
                /* index转化为grid的index */
                var gridIndexs = new Array();
                if (this.deleteRows.length > 0) {

                    for (var i = 0; i < this.deleteRows.length; i++) {
                        var row = this.deleteRows[i];
                        var dataObj = row.data;
                        var idValue = dataObj[oThis.options.idField].value;
                        var node = oThis.tree.getNodeByParam('id', idValue);
                        oThis.tree.removeNode(node)
                    }

                }
            });

            this.dataTable.on($.DataTable.ON_DELETE_ALL, function(event) {
                var nodes = oThis.tree.getNodes();
                for (var i = 0, l = nodes.length; i < l; i++) {
                    var node = oThis.tree.getNodeByParam('id', nodes[i].id);
                    oThis.tree.removeNode(node);
                    i--;
                    l = nodes.length;
                }
            });

            // 加载数据,只考虑viewModel传入grid
            this.dataTable.on($.DataTable.ON_LOAD, function(data) {
                var data = oThis.dataTable.rows();
                if (data.length > 0) {
                    var values = new Array();
                    $.each(data, function() {
                        var value = {};
                        var dataObj = this.data;
                        var idValue = dataObj[oThis.options.idField].value;
                        var pidValue = dataObj[oThis.options.pidField].value;
                        var nameValue = dataObj[oThis.options.nameField].value;

                        value['id'] = idValue;
                        value['pId'] = pidValue;
                        value['name'] = nameValue;
                        treeData.push(value);
                    });
                }

                this.tree = $.fn.zTree.init(this.$element, treeSetting, treeData);
            });

            this.dataTable.on($.DataTable.ON_VALUE_CHANGE, function(event) {
                var row = oThis.dataTable.getRowByRowId(event.rowId)
                if (!row) return
                var id = row.getValue(oThis.options.idField)
                var node = oThis.tree.getNodeByParam('id', id);

                var field = event.field;
                var value = event.newValue;
                if (oThis.options.nameField == field){
                    node.name = value
                    oThis.tree.updateNode(node)
                }
                else if (oThis.options.pidField == field){
                    var targetNode = oThis.tree.getNodeByParam('id', value);
                    oThis.tree.moveNode(targetNode, node,"inner")
                }
            });
            // 通过树id获取dataTable的rowId
            this.getRowIdByIdValue = function(idValue) {
                var oThis = this;
                var rowId = null;
                $.each(this.dataTable.rows(), function() {
                    var dataObj = this.data;
                    var id = this.rowId;
                    if (dataObj[oThis.options.idField].value == idValue) {
                        rowId = id;
                    }
                })
                return rowId;
            }

            return this;
        }

        Tree.getName = function() {
            return 'tree'
        }
        if ($.compManager)
            $.compManager.addPlug(Tree)

    }($);
    +function($) {

        var Combobox = $.InputComp.extend({
            initialize: function(element, options, viewModel) {
                var self = this
                Combobox.superclass.initialize.apply(this, arguments)
                this.datasource = $.getJSObject(viewModel, options['datasource'])
                this.single = options.single
                this.mutil = options.mutil
                this.validType = 'combo'
                if ($(this.element).children().length > 0)
                    this.comboEle = $(this.element).find('div')[0]
                else
                    this.comboEle = this.element
                this.create()
                // $(this.comboEle).attr('contenteditable', true)
                if(this.mutil){
                    $(this.comboEle).on("mutilSelect",function(event,value){
                        self.setValue(value)
                    })
                }

                this.comp = $(this.comboEle).Combobox({
                    readchange:false,
                    dataSource: this.datasource,
                    single:this.single,
                    mutil:this.mutil,
                    onSelect: function(item) {
                        self.setValue(item.pk)
                        self.trigger('onSelect',item)
// if (self.onSelect) {
// self.onSelect(item)
// }
                    }
                })
            },
            /**
             * 增加dom事件
             *
             * @param {String}
             *            name
             * @param {Function}
             *            callback
             */
            addDomEvent: function(name, callback){
                $(this.comboEle).on(name, callback)
                return this
            },
            /**
             * 移除dom事件
             *
             * @param {String}
             *            name
             */
            removeDomEvent: function(name){
                $(this.comboEle).off(name)
            },
            modelValueChange: function(value) {
                if (this.slice) return
// value = value || ""
                this.trueValue = value
                $(this.comboEle).val(value);

            },
            setValue: function(value) {
                this.trueValue = value
                $(this.comboEle).val(value);
                this.slice = true
                this.setModelValue(this.trueValue)
                this.slice = false
                this.trigger(Combobox.EVENT_VALUE_CHANGE, this.trueValue)
            },
            getValue: function() {
                return this.trueValue
            },
            setEnable: function(enable) {
                if (enable === true || enable === 'true') {
                    this.enable = true
                    $(this.comboEle).data("enable",true)
                    $(this.comboEle).parent().removeClass('disablecover').parent().find('.covershade').remove()
                } else if (enable === false || enable === 'false') {
                    this.enable = false
                    $(this.comboEle).data("enable",false)
                    $(this.comboEle).parent().addClass('disablecover').parent().prepend('<div class="covershade"></div>')

                }
            },
            Statics: {
                compName: 'combo'
            }
        })

        if ($.compManager)
            $.compManager.addPlug(Combobox)

    }($);

    +function($) {

        var StringComp = $.InputComp.extend({
            initialize: function(element, options, viewModel) {
                var self = this
                StringComp.superclass.initialize.apply(this, arguments)
                this.validType = 'string'
                this.maxLength = options['maxLength']
                this.minLength = options['minLength']
                if (this.dataModel) {
                    if (this.hasDataTable) {
                        this.minLength = this.dataModel.getMeta(this.field, "minLength") || this.minLength
                        this.maxLength = this.dataModel.getMeta(this.field, "maxLength") || this.maxLength
                    }
                }
                this.create()
                if (this.element.nodeName == 'INPUT') {
                    $(this.element).focusin(function(e) {
                        self.setShowValue(self.getValue())
                    })
                    $(this.element).blur(function(e) {
                        self.setValue(self.element.value)
                    })
                }
            },

            modelValueChange: function(value) {
                if (this.slice) return
                value = value || ""
                this.trueValue = value
                this.showValue = value// this.masker.format(value).value
                this.setShowValue(this.showValue)
            },
            setValue: function(value) {
                this.trueValue = value// this.formater.format(value)
                this.showValue = value// this.masker.format(value).value
                this.setShowValue(this.showValue)
                this.slice = true
                this.setModelValue(this.trueValue)
                this.slice = false
                this.trigger(StringComp.EVENT_VALUE_CHANGE, this.trueValue)
            },
            getValue : function() {
                return this.trueValue
            },
            setShowValue : function(showValue) {
                this.showValue = showValue
                this.element.value = showValue
                this.element.title = showValue
            },
            getShowValue: function() {
                return this.showValue
            },

            Statics: {
                compName: 'string'
            }
        })

        $.StringComp = StringComp
        if ($.compManager)
            $.compManager.addPlug(StringComp)

    }($);
    /* autocomplete组件 add by songhlc */
    +function($) {

        var AutoCompleteComp = $.InputComp.extend({
            initialize: function(element, options, viewModel) {
                var self = this
                AutoCompleteComp.superclass.initialize.apply(this, arguments)
                this.validType = 'string'
                this.maxLength = options['maxLength']
                this.minLength = options['minLength']
                if (this.dataModel) {
                    if (this.hasDataTable) {
                        this.minLength = this.dataModel.getMeta(this.field, "minLength") || this.minLength
                        this.maxLength = this.dataModel.getMeta(this.field, "maxLength") || this.maxLength
                    }
                }
                this.create()
                if (this.element.nodeName == 'INPUT') {
                    $(this.element).focusin(function(e) {
                        self.setShowValue(self.getValue())
                    })
                    $(this.element).blur(function(e) {
                        self.setValue(self.element.value)
                    })
                    if($(this.element).autocomplete){
                        $(this.element).autocomplete(options['autoType']());
                    }

                }
            },

            modelValueChange: function(value) {
                if (this.slice) return
                value = value || ""
                this.trueValue = value
                this.showValue = value// this.masker.format(value).value
                this.setShowValue(this.showValue)
            },
            setValue: function(value) {
                this.trueValue = value// this.formater.format(value)
                this.showValue = value// this.masker.format(value).value
                this.setShowValue(this.showValue)
                this.slice = true
                this.setModelValue(this.trueValue)
                this.slice = false
                this.trigger(AutoCompleteComp.EVENT_VALUE_CHANGE, this.trueValue)
            },
            getValue : function() {
                return this.trueValue
            },
            setShowValue : function(showValue) {
                this.showValue = showValue
                this.element.value = showValue
                this.element.title = showValue
            },
            getShowValue: function() {
                return this.showValue
            },

            Statics: {
                compName: 'autocomplete'
            }
        })

        $.AutoCompleteComp = AutoCompleteComp
        if ($.compManager)
            $.compManager.addPlug(AutoCompleteComp)

    }($);
    +function($ ) {
        var CheckboxComp = $.InputComp.extend({
            initialize: function(element, options, viewModel) {

                var self = this
                CheckboxComp.superclass.initialize.apply(this, arguments)
                this.create()

                if($.app){
                    $(this.element).wrap("<label class='label-switch'></label>").after("<div class='checkbox'></div>").css("display","none")

                }else{
                    if($(this.element).parent(".checkbox").length === 0 && !iweb.browser.isIE8){
                        $(this.element).wrap("<div class='checkbox check-success'></div>").after("<label for="+element.id+"></label>")
                    }else if(iweb.browser.isIE8){
                        $(this.element).wrap("<div></div>")
                    }

                }
                $(this.element).on('change',function(){
                    var val = element.checked ? 'Y' : 'N'

                    self.setValue(val)
                })

            },

            modelValueChange: function(val) {
                if (this.slice) return
                val = val || ""
                this.trueValue = val
                if (val == 'Y' || val == 'true') {
                    this.showValue = true;
                } else if (val == 'N' || val == 'false') {
                    this.showValue = false;
                } else {
                    this.showValue = false;
                }
                this.setShowValue(this.showValue)
            },
            setValue: function(val) {
                this.trueValue = val
                if (val == 'Y' || val == 'true') {
                    this.showValue = true;
                } else if (val == 'N' || val == 'false') {
                    this.showValue = false;
                } else {
                    this.showValue = false;
                }
                this.setShowValue(this.showValue)
                this.slice = true
                this.setModelValue(this.trueValue)
                this.slice = false
                this.trigger(CheckboxComp.EVENT_VALUE_CHANGE, this.trueValue)
            },
            getValue: function() {
                return this.trueValue
            },
            setShowValue: function(showValue) {
                this.showValue = showValue
                this.element.checked = showValue
            },
            getShowValue: function() {
                return this.showValue
            },
            setEnable: function(enable) {
                if (enable === true || enable === 'true') {
                    this.enable = true
                    $(this.element).parent().removeClass('disablecover').parent().find('.covershade').remove()
                } else if (enable === false || enable === 'false') {
                    this.enable = false
                    var tmpelement = $(this.element)
                    if(tmpelement.parent().hasClass('disablecover')){ return};
                    tmpelement.parent().addClass('disablecover').before('<div class="covershade"></div>')
                }
            },

            Statics: {
                compName: 'check'
            }
        })

        if ($.compManager)
            $.compManager.addPlug(CheckboxComp)

    }($);

    +function($) {


        var CheckboxGroupComp = $.InputComp.extend({
            initialize: function(element, options, viewModel) {
                var self = this
                this.pks = [];
                CheckboxGroupComp.superclass.initialize.apply(this, arguments)
                this.validType = 'checkboxGroup'
                var datasource = $.getJSObject(viewModel, options['datasource'])

                if(!$.isArray(datasource)) return;

                var checkboxTemplate = $(this.element).children();

                if(!checkboxTemplate.is(":checkbox"))return;

                // modify by songhlc juggle---
                var checkboxCtn = $("<div></div>");
                for(var i=0,len = (datasource.length-1);i<=len;i++){
                    var checkItemCtn = $("<div class='checkbox checkbox-primary'></div>");
                    var clonedTemplate = checkboxTemplate.clone();
                    var curId = self.id+"_"+i;
                    // find('[type=radio]')
                    $(clonedTemplate.get(0)).attr("id",curId).appendTo(checkItemCtn);
                    // find('[data-role=name]')
                    $(clonedTemplate.get(1)).attr("for",curId).appendTo(checkItemCtn);
                    checkItemCtn.appendTo(checkboxCtn);
                }
                $(this.element).html('').append(checkboxCtn);

                var allCheckbox =  $(this.element).find('[type=checkbox]');
                var allName = $(this.element).find('[data-role=name]');
                for(var k=0;k<allCheckbox.length;k++){
                    allCheckbox[k].value = datasource[k].pk
                    allName[k].innerHTML = datasource[k].name
                    this.pks.push(datasource[k].pk)
                }

                this.valArr = [];
                this.create()

                $(this.element).find(":checkbox").each(function() {
                    $(this).on('click', function() {

                        if(self.valArr.length == 0){
                            if(this.checked){
                                self.valArr.push(this.value)
                            }
                        }else{
                            if(this.checked){
                                var mark = null;
                                for(var i=0;i<self.valArr.length;i++){
                                    if(this.value == self.valArr[i]){
                                        mark = i;
                                    }
                                }

                                if(mark == null){
                                    self.valArr.push(this.value)
                                }

                            }else{

                                for(var k=0;k<self.valArr.length;k++){
                                    if(this.value == self.valArr[k]){
                                        self.valArr.splice(k,1)
                                    }
                                }

                            }
                        }
                        // 填值
                        self.setValue(self.valArr.toString())

                    })
                })
            },

            modelValueChange: function(val) {
                if (this.slice) return

                if(val !='' && val != null){
                    this.valArr = val.split(',');
                }

                this.setValue(val)
            },
            setValue: function(val) {
                this.trueValue = val
                if(val == '' || val == null){
                    var manualVal = ''
                }else{
                    manualVal = val.split(',');
                }

                var pks = this.pks.slice();
                for(var k=0;k<pks.length;k++){
                    var pk = pks[k]
                    if(manualVal.indexOf(pk) !== -1){
                        pks.splice(k,1);
                        --k;
                    }

                }

                $(this.element).find(":checkbox").each(function() {
// for(var i=0;i<manualVal.length;i++){
// if(this.value == manualVal[i]){
// this.checked = true;
// }
// }

                    if(manualVal.indexOf(this.value) !== -1){
                        this.checked = true
                    }

                    if(pks.indexOf(this.value) !== -1){
                        this.checked = false
                    }
                })
                this.slice = true
                this.setModelValue(this.trueValue)
                this.slice = false
                this.trigger(CheckboxGroupComp.EVENT_VALUE_CHANGE, this.trueValue)
            },
            getValue: function() {
                return this.trueValue
            },

            Statics: {
                compName: 'checkboxGroup'
            }
        })

        if ($.compManager)
            $.compManager.addPlug(CheckboxGroupComp)

    }($);

    +function($) {

        var DateTime = $.InputComp.extend({
            initialize: function(element, options, viewModel) {
                var self = this
                this.outerDiv = element
                element = $(element).find('input')[0]
                DateTime.superclass.initialize.apply(this, arguments)
                this.maskerMeta = iweb.Core.getMaskerMeta('datetime') || {}
                this.maskerMeta.format = options['format'] || this.maskerMeta.format

                if (this.dataModel) {
                    // 处理数据精度
                    if (this.hasDataTable) {
                        // this.dataModel.refRowMeta(this.field,
                        // "format").subscribe(function(format){
                        // self.setFormat(format)
                        // })
                        this.dataModel.on(this.field + '.format.' +  $.DataTable.ON_CURRENT_META_CHANGE, function(event){
                            self.setFormat(event.newValue)
                        });

                        this.maskerMeta.format = this.dataModel.getMeta(this.field, "format") || this.maskerMeta.format
                    }
                }
                // this.validType = 'datetime'
                if(!this.options.widgetParent){
                    this.options.widgetParent = $("body")
                }
                this.options.picker_type = "datetime";
                this.options.picker_type = "datetime";
                if(!options['format'])
                    this.options.format = "YYYY-MM-DD HH:mm:ss";
                this.formater = new $.DateFormater(this.maskerMeta.format);
                this.masker = new DateTimeMasker(this.maskerMeta);
                element.value = this.getValue();
                this.create()
                this.comp = $(this.outerDiv).datetimepicker(this.options)
                // $(this.element).focusin(function(e) {
                // self.setShowValue(self.getValue())
                //
                // }).blur(function(e) {
                // if (!self.doValidate() && self._needClean()){
                // //self.element.value = self.getShowValue()
                // self.setShowValue(self.getShowValue())
                // }
                // else
                // //self.setValue(self.element.value)
                // self.setValue(this.value)
                // })
                if($.app){
                    $(this.element).on("picker_open",function(){
                        self.setShowValue(self.getValue())
                    }).on("picker_close",function(){
                        self.setValue(this.value)
                    })
                }
            },
            create: function() {
                var self = this
                if (this.dataModel) {
                    // 处理数据绑定
                    if (this.hasDataTable) {

                        this.dataModel.on(this.field + "." + $.DataTable.ON_CURRENT_VALUE_CHANGE, function (event) {
                            self.modelValueChange(event.newValue);
                        });


                        this.dataModel.on($.DataTable.ON_ENABLE_CHANGE, function (event) {
                            if (event.enable === true) {
                                var _enable = self.dataModel.getRowMeta(self.field, 'enable');
                                if (_enable === true)
                                    self.setEnable(_enable);
                            } else {
                                self.setEnable(event.enable);
                            }
                        });

                        this.dataModel.on(this.field + '.enable.' + $.DataTable.ON_CURRENT_META_CHANGE, function (event) {
                            self.setEnable(event.newValue);
                        });

                        this.dataModel.on(this.field + '.enable.' + $.DataTable.ON_ROW_META_CHANGE, function (event) {
                            self.setEnable(event.newValue);
                        });


                        this.dataModel.on(this.field + '.required.' + $.DataTable.ON_CURRENT_META_CHANGE, function (event) {
                            self.setRequired(event.newValue);
                        });

                        this.dataModel.on(this.field + '.regExp.' + $.DataTable.ON_CURRENT_META_CHANGE, function (event) {
                            self.regExp = event.newValue;
                        });
                        this.dataModel.on($.DataTable.ON_CURRENT_ROW_CHANGE, function () {
                            var row = self.dataModel.getCurrentRow();
                            if (!row) {
                                self.modelValueChange('');
                                self.setEnable(false);
                            } else {
                                self.modelValueChange(row.getValue(self.field));
                                if (this.enable === true) {
                                    var _enable = row.getMeta(self.field, 'enable');
                                    if (_enable === true)
                                        self.setEnable(_enable);
                                } else {
                                    self.setEnable(this.enable);
                                }
                                self.setRequired(row.getMeta(self.field, 'required'));
                            }
                        });
                        this.dataModel.on($.DataTable.ON_CURRENT_UPDATE, function (event) {
                            var row = event.rows[0]
                            self.modelValueChange(row.getValue(self.field));
                        });

                        this.setEnable(this.dataModel.isEnable(this.field))
                        this.setRequired(this.dataModel.getMeta(this.field, "required"))
                        this.regExp = this.dataModel.getMeta(this.field, "regExp")
                    } else {
                        this.dataModel.subscribe(function (value) {
                            self.modelValueChange(value)
                        })
                    }
                    this.modelValueChange(this.hasDataTable ? this.dataModel.getValue(this.field) : this.dataModel())
                }

                $(this.element).focus(function(e) {
                    if($(".dropdown-menu").length == 0) {
                        self.onFocusin ? self.onFocusin(e) : self.setShowValue(self.getValue())
                    }
                    // $(this).select();
                })
                $(this.element).on('change.date',function(e) {
                    if (!self.doValidate() && self._needClean()){
                        self.element.value = self.getShowValue()
                        // self.setValue(self.getValue())
                    }
                    else
                        self.setValue(self.element.value)
                })



            },
            modelValueChange: function(value) {
                if (this.slice) return
                value = value || ""
                this.trueValue = value
                var showValue = this.masker.format(value).value
                this.setShowValue(showValue)
            },
            setValue: function(value) {
                this.trueValue = value
                this.setShowValue(this.trueValue) // TODO fomat格式
                this.slice = true
                this.setModelValue(value)
                this.slice = false
                this.trigger(DateTime.EVENT_VALUE_CHANGE, this.trueValue)
            },
            getValue : function() {
                return this.trueValue
            },
            setShowValue : function(showValue) {
                this.showValue = showValue
// this.element.value = showValue
                $(this.element).val(showValue);
                if($(this.outerDiv).data("DateTimePicker")){
                    $(this.outerDiv).data("DateTimePicker").date(showValue)
                }
            },
            getShowValue: function() {
                return this.showValue
            },
            /**
             * 修改显示格式
             *
             * @param {Integer}
             *            precision
             */
            setFormat: function(format){

                if (this.maskerMeta.format == format) return
                this.maskerMeta.format = format
                this.formater = new $.DateFormater(this.maskerMeta.format);
                this.masker = new DateTimeMasker(this.maskerMeta);
            },
            setEnable: function(enable) {
                if (enable === true || enable === 'true') {
                    this.enable = true
                    if(!$.app){
                        $(this.element).removeAttr('readonly')
                    }
                    $(this.element).attr('h7picker','true')
                    $(this.element).parent().removeClass('disablecover')

                } else if (enable === false || enable === 'false') {
                    this.enable = false
                    $(this.element).attr('h7picker','false')
                    $(this.element).attr('readonly', 'readonly')
                    $(this.element).parent().addClass('disablecover')

                }
            },
            Statics: {
                compName: 'datetime'
            }
        })

        var DateComp = DateTime.extend({
            initialize: function(element, options, viewModel) {
                var self = this
                this.outerDiv = element
                element = $(element).find('input')[0]
                DateTime.superclass.initialize.apply(this, arguments)
                this.maskerMeta = iweb.Core.getMaskerMeta('date') || {}
                this.maskerMeta.format = options['format'] || this.maskerMeta.format

                if (this.dataModel) {
                    // 处理数据精度
                    if (this.hasDataTable) {
                        // this.dataModel.refRowMeta(this.field,
                        // "format").subscribe(function(format){
                        // self.setFormat(format)
                        // })
                        this.dataModel.on(this.field + '.format.' +  $.DataTable.ON_CURRENT_META_CHANGE, function(event){
                            self.setFormat(event.newValue)
                        });

                        this.maskerMeta.format = this.dataModel.getMeta(this.field, "format") || this.maskerMeta.format

                    }
                }
                // this.validType = 'date'
                if(!this.options.widgetParent){
                    this.options.widgetParent = $("body")
                }
                this.options.picker_type = "datecomp";
                if(!options['format'])
                    this.options.format = "YYYY-MM-DD";
                this.formater = new $.DateFormater(this.maskerMeta.format);
                this.masker = new DateMasker(this.maskerMeta);
                element.value = this.getValue();
                this.create()

                this.comp = $(this.outerDiv).datetimepicker(this.options)
                // $(this.element).focusin(function(e) {
                // self.setShowValue(self.getValue())
                //
                // }).on('blur',function(e) {
                // if (!self.doValidate() && self._needClean()){
                // //self.element.value = self.getShowValue()
                // self.setShowValue(self.getShowValue())
                // }
                // else
                // //self.setValue(self.element.value)
                // self.setValue(this.value)
                // })
            },
            /**
             * 修改显示格式
             *
             * @param {Integer}
             *            precision
             */
            setFormat: function(format){
                if (this.maskerMeta.format == format) return
                this.maskerMeta.format = format
                this.formater = new $.DateFormater(this.maskerMeta.format);
                this.masker = new DateMasker(this.maskerMeta);
            },
            Statics: {
                compName: 'date'
            }
        })
        var TimeComp = DateTime.extend({
            initialize: function(element, options, viewModel) {
                var self = this
                this.outerDiv = element
                element = $(element).find('input')[0]
                DateTime.superclass.initialize.apply(this, arguments)
                this.maskerMeta = iweb.Core.getMaskerMeta('time') || {}
                this.maskerMeta.format = options['format'] || this.maskerMeta.format

                if (this.dataModel) {
                    // 处理数据精度
                    if (this.hasDataTable) {
                        // this.dataModel.refRowMeta(this.field,
                        // "format").subscribe(function(format){
                        // self.setFormat(format)
                        // })
                        this.dataModel.on(this.field + '.format.' +  $.DataTable.ON_CURRENT_META_CHANGE, function(event){
                            self.setFormat(event.newValue)
                        });

                        this.maskerMeta.format = this.dataModel.getMeta(this.field, "format") || this.maskerMeta.format

                    }
                }
                // this.validType = 'date'
                if(!this.options.widgetParent){
                    this.options.widgetParent = $("body")
                }
                this.options.picker_type = "timecomp";
                if(!options['format'])
                    this.options.format = "HH:mm:ss";
                this.formater = new $.DateFormater(this.maskerMeta.format);
                this.masker = new DateMasker(this.maskerMeta);
                element.value = this.getValue();
                this.create()

                this.comp = $(this.outerDiv).datetimepicker(this.options)
                // $(this.element).focusin(function(e) {
                // self.setShowValue(self.getValue())
                //
                // }).blur(function(e) {
                // if (!self.doValidate() && self._needClean()){
                // //self.element.value = self.getShowValue()
                // self.setShowValue(self.getShowValue())
                // }
                // else
                // //self.setValue(self.element.value)
                // self.setValue(this.value)
                // })
            },
            /**
             * 修改显示格式
             *
             * @param {Integer}
             *            precision
             */
            setFormat: function(format){
                if (this.maskerMeta.format == format) return
                this.maskerMeta.format = format
                this.formater = new $.DateFormater(this.maskerMeta.format);
                this.masker = new DateMasker(this.maskerMeta);
            },
            Statics: {
                compName: 'time'
            }
        })
        if ($.compManager){
            $.compManager.addPlug(DateTime)
            $.compManager.addPlug(DateComp)
            $.compManager.addPlug(TimeComp)
        }

    }($);
    +function($) {

        var RadioComp = $.InputComp.extend({
            initialize: function(element, options, viewModel) {
                // var self = this;
                RadioComp.superclass.initialize.apply(this, arguments);
                var datasource = $.getJSObject(viewModel, options['datasource']);

                if(!$.isArray(datasource)) return;

                this.radioTemplate = $(this.element).children();

                // if(!radioTemplate.is(":radio"))return;
                //
                // for(var i=0,len = (datasource.length-1);i<len;i++){
                // radioTemplate.clone().appendTo(this.element)
                // }
                //
                // this.radioTemplate = radioTemplate;
                //
                // var allRadio = $(this.element).children('[type=radio]');
                // var allName = $(this.element).children('[data-role=name]');
                // for(var k=0;k<allRadio.length;k++){
                // allRadio[k].value = datasource[k].pk
                // allName[k].innerHTML = datasource[k].name
                // }
                //
                // this.radioInputName = allRadio[0].name;
                this.setComboData(datasource);
                this.create()

                // $(this.element).find(":radio[name='" + this.radioInputName +
                // "']").each(function() {
                // $(this).on('click', function() {
                // if (this.checked) {
                // self.setValue(this.value)
                // }
                // })
                // })
            },
            setComboData: function(comboData){
                var self = this;
                if(!this.radioTemplate.is(":radio")) return;
                this.element.innerHTML = '';
                /* add by songhlc 修改radio的样式 juggle---*/
                var radioCtn = $("<div></div>");
                for(var i=0,len = comboData.length;i<len ;i++){
                    var radioItemCtn = $("<div class='radio radio-primary radio-inline'></div>");
                    var clonedTemplate = this.radioTemplate.clone();
                    var curId = self.id+"_"+i;
                    // find('[type=radio]')
                    $(clonedTemplate.get(0)).attr("id",curId).appendTo(radioItemCtn);
                    // find('[data-role=name]')
                    $(clonedTemplate.get(1)).attr("for",curId).appendTo(radioItemCtn);
                    radioItemCtn.appendTo(radioCtn);
                }
                $(this.element).append(radioCtn);
                // modify by songhlc 修改radio样式
                var allRadio =  $(this.element).find('[type=radio]');
                var allName = $(this.element).find('[data-role=name]');
                for(var k=0;k<allRadio.length;k++){
                    allRadio[k].value = comboData[k].pk
                    allName[k].innerHTML = comboData[k].name
                }

                this.radioInputName = allRadio[0].name;

                $(this.element).find(":radio[name='" + this.radioInputName + "']").each(function() {
                    $(this).on('click', function() {
                        if (this.checked) {
                            self.setValue(this.value)
                        }
                    })
                })

            },
            modelValueChange: function(val) {
                if (this.slice) return

                this.setValue(val)
            },
            setValue: function(val) {
                this.trueValue = val
                $(this.element).find(":radio[name='" + this.radioInputName + "']").each(function() {
                    if (this.value == val) {
                        this.checked = true;
                    }else{
                        this.checked = false;
                    }
                })
                this.slice = true
                this.setModelValue(this.trueValue)
                this.slice = false
                this.trigger(RadioComp.EVENT_VALUE_CHANGE, this.trueValue)
            },
            getValue: function() {
                return this.trueValue
            },

            Statics: {
                compName: 'radio'
            }
        })

        if ($.compManager)
            $.compManager.addPlug(RadioComp)

    }($);

    +function($) {
        var IntegerComp = $.InputComp.extend({
            initialize: function(element, options, viewModel) {
                var self = this
                IntegerComp.superclass.initialize.apply(this, arguments)
                this.validType='integer'
                this.max = options['max']
                this.min = options['min']
                this.maxNotEq = options['maxNotEq']
                this.minNotEq = options['minNotEq']
                this.maxLength = options['maxLength']?options['maxLength']:25
                this.minLength = options['mixLength']?options['mixLength']:0

                if (this.dataModel) {
                    if (this.hasDataTable) {
                        this.min = this.dataModel.getMeta(this.field, "min") !== undefined ? this.dataModel.getMeta(this.field, "min") : this.min
                        this.max = this.dataModel.getMeta(this.field, "max") !== undefined ? this.dataModel.getMeta(this.field, "max") : this.max
                        this.minNotEq = this.dataModel.getMeta(this.field, "minNotEq") !== undefined ? this.dataModel.getMeta(this.field, "minNotEq") : this.minNotEq
                        this.maxNotEq = this.dataModel.getMeta(this.field, "maxNotEq") !== undefined ?  this.dataModel.getMeta(this.field, "maxNotEq") : this.maxNotEq
                        this.minLength = $.isNumeric(this.dataModel.getMeta(this.field, "minLength")) ? this.dataModel.getMeta(this.field, "minLength"):this.minLength
                        this.maxLength = $.isNumeric(this.dataModel.getMeta(this.field, "maxLength")) ? this.dataModel.getMeta(this.field, "maxLength"):this.maxLength

                    }
                }

                this.create()

            },
            modelValueChange: function(value) {
                if (this.slice) return
                value = value || ""
                this.trueValue = value
                this.showValue = value // this.masker.format(value).value
                this.setShowValue(this.showValue)
            },
            setValue: function(value) {
                this.trueValue = value // this.formater.format(value)
                this.showValue = value // this.masker.format(value).value
                this.setShowValue(this.showValue)
                this.slice = true
                this.setModelValue(this.trueValue)
                this.slice = false
                this.trigger(IntegerComp.EVENT_VALUE_CHANGE, this.trueValue)
            },
            getValue : function() {
                return this.trueValue
            },
            setShowValue : function(showValue) {
                this.showValue = showValue
                this.element.value = showValue
            },
            getShowValue: function() {
                return this.showValue
            },

            Statics: {
                compName: 'integer'
            }
        })

        if ($.compManager)
            $.compManager.addPlug(IntegerComp)

    }($);

    +function($) {

        /**
         * 货币控件
         */
        var CurrencyComp = $.InputComp.extend({
            initialize: function(element, options, viewModel) {
                var self = this
                CurrencyComp.superclass.initialize.apply(this, arguments)
                this.maskerMeta = iweb.Core.getMaskerMeta('currency') || {}
                this.maskerMeta.precision = options['precision'] ||  this.maskerMeta.precision
                this.maskerMeta.curSymbol = options['curSymbol'] ||  this.maskerMeta.curSymbol
                this.validType = 'float'
                this.max = options['max']
                this.min = options['min']
                this.maxNotEq = options['maxNotEq']
                this.minNotEq = options['minNotEq']
                this.maxLength = options['maxLength']?options['maxLength']:25
                this.minLength = options['mixLength']?options['mixLength']:0
                if (this.dataModel) {
                    // 处理数据精度
                    if (this.hasDataTable) {
                        // this.dataModel.refRowMeta(this.field,
                        // "precision").subscribe(function(precision){
                        // self.setPrecision(precision)
                        // })
                        this.dataModel.on(this.field + '.precision.' +  $.DataTable.ON_CURRENT_META_CHANGE, function(event){
                            self.setPrecision(event.newValue)
                        });
                        this.maskerMeta.precision = this.dataModel.getMeta(this.field, "precision") || this.maskerMeta.precision
                        // this.dataModel.refRowMeta(this.field,
                        // "curSymbol").subscribe(function(symbol){
                        // self.setCurSymbol(symbol)
                        // })
                        this.dataModel.on(this.field + '.curSymbol.' +  $.DataTable.ON_CURRENT_META_CHANGE, function(event){
                            self.setCurSymbol(event.newValue)
                        });

                        this.maskerMeta.curSymbol = this.dataModel.getMeta(this.field, "curSymbol") || this.maskerMeta.curSymbol
                        this.min = this.dataModel.getMeta(this.field, "min") !== undefined ? this.dataModel.getMeta(this.field, "min") : this.min
                        this.max = this.dataModel.getMeta(this.field, "max") !== undefined ? this.dataModel.getMeta(this.field, "max") : this.max
                        this.minNotEq = this.dataModel.getMeta(this.field, "minNotEq") !== undefined ? this.dataModel.getMeta(this.field, "minNotEq") : this.minNotEq
                        this.maxNotEq = this.dataModel.getMeta(this.field, "maxNotEq") !== undefined ?  this.dataModel.getMeta(this.field, "maxNotEq") : this.maxNotEq
                        this.minLength = $.isNumeric(this.dataModel.getMeta(this.field, "minLength")) ? this.dataModel.getMeta(this.field, "minLength"):this.minLength
                        this.maxLength = $.isNumeric(this.dataModel.getMeta(this.field, "maxLength")) ? this.dataModel.getMeta(this.field, "maxLength"):this.maxLength

                    }
                }
                this.formater = new $.NumberFormater(this.maskerMeta.precision);
                this.masker = new CurrencyMasker(this.maskerMeta);
                this.create()
            },
            modelValueChange: function(value) {
                if(value === null || typeof value == "undefined")
                    value = value || ""
                this.maskerMeta.precision = this.dataModel.getRowMeta(this.field, "precision") || this.maskerMeta.precision
                this.maskerMeta.curSymbol = this.dataModel.getRowMeta(this.field, "curSymbol") || this.maskerMeta.curSymbol
                this.formater.precision = this.maskerMeta.precision;
                this.masker.formatMeta.curSymbol  = this.maskerMeta.curSymbol
                // this.trueValue = value
                // var formatValue = this.formater.format(this.trueValue)
                var formatValue = this.formater.format(value)
                this.trueValue = formatValue
                this.element.trueValue = this.trueValue
                this.showValue = this.masker.format(formatValue).value
                this.setShowValue(this.showValue)
            },
            setValue: function(value) {
                this.maskerMeta.precision = this.dataModel.getRowMeta(this.field, "precision") || this.maskerMeta.precision
                this.formater.precision = this.maskerMeta.precision;
                var mvalue = this.dataModel.getCurrentRow().getValue(this.field)
                if(value == mvalue) {
                    this.showValue = this.masker.format(this.trueValue).value
                    this.setShowValue(this.showValue)
                } else {
                    this.trueValue = this.formater.format(value)
                    this.element.trueValue = this.trueValue
                    this.showValue = this.masker.format(this.trueValue).value
                    this.setShowValue(this.showValue)
                    this.setModelValue(this.trueValue)
                    this.trigger(CurrencyComp.EVENT_VALUE_CHANGE, this.trueValue)
                }

            },
            getValue : function() {
                return this.trueValue
            },
            setShowValue : function(showValue) {
                this.showValue = showValue
                this.element.value = showValue
            },
            getShowValue: function() {
                return this.showValue
            },
            /**
             * 修改精度
             *
             * @param {Integer}
             *            precision
             */
            setPrecision: function(precision){
                if (this.maskerMeta.precision == precision) return
                this.maskerMeta.precision =precision
                this.formater = new $.NumberFormater(this.maskerMeta.precision);
                this.masker = new CurrencyMasker(this.maskerMeta);
                var currentRow = this.dataModel.getCurrentRow();
                if(currentRow){
                    var v = this.dataModel.getCurrentRow().getValue(this.field)
                    this.showValue = this.masker.format(this.formater.format(v)).value
                }else{
                    this.showValue = this.masker.format(this.formater.format(this.trueValue)).value
                }
                this.setShowValue(this.showValue)
            },
            /**
             * 修改币符
             *
             * @param {String}
             *            curSymbol
             */
            setCurSymbol: function(curSymbol){
                if (this.maskerMeta.curSymbol == curSymbol) return
                this.maskerMeta.curSymbol = curSymbol
                this.masker.formatMeta.curSymbol  = this.maskerMeta.curSymbol
                this.element.trueValue = this.trueValue
                this.showValue = this.masker.format(this.trueValue).value
                this.setShowValue(this.showValue)

            },
            onFocusin: function(e) {
                var v = this.getValue(),vstr = v+'',focusValue = v
                if($.isNumeric(v) && $.isNumeric(this.maskerMeta.precision)) {
                    if(vstr.indexOf('.') >= 0) {
                        var sub = vstr.substr(vstr.indexOf('.')+1)
                        if(sub.length < this.maskerMeta.precision || parseInt(sub.substr(this.maskerMeta.precision)) == 0) {
                            focusValue = this.formater.format(v)
                        }
                    } else if(this.maskerMeta.precision > 0){
                        focusValue = this.formater.format(v)
                    }
                }
                this.setShowValue(focusValue)

            },
            Statics: {
                compName: 'currency'
            }
        })

        if ($.compManager)
            $.compManager.addPlug(CurrencyComp)

    }($);

    +function($) {
        var Multilang = $.InputComp.extend({
            initialize: function(element, options, viewModel) {
                var self = this
                Multilang.superclass.initialize.apply(this, arguments)
                this.create()
                var multinfo =  iweb.Core.getLanguages()
                if(options.multinfo){
                    multinfo = options.multinfo
                }

                var multidata = [];
                this.field = options.field;
                multinfo.lang_name =  options.field
                for(i = 0; i < multinfo.length; i++){
                    if(i){
                        multidata[i] =  this.dataModel.getValue(this.field + (i+1),this.dataTableRow)
                    }else{
                        multidata[i] =  this.dataModel.getValue(this.field,this.dataTableRow)
                    }

                }


                this.multinfo = multinfo;
                this.multidata = multidata;
                $(element).multilang({"multinfo":multinfo, "multidata":multidata});

                this.$element = $(element)
                this.$element.on('change.u.multilang', function(event, valObj) {

                    self.setModelValue(valObj)
                })
            },
            create: function() {
                var self = this
                if (this.dataModel) {
                    // 处理数据绑定
                    if (this.hasDataTable) {
                        // this.dataModel.ref(this.field).subscribe(function(value)
                        // {
                        // self.modelValueChange(value)
                        // })
                        this.dataModel.on($.DataTable.ON_CURRENT_ROW_CHANGE, function(event){
                            self.modelValueChange();
                        });

                        // 处理只读
                        // this.dataModel.refEnable(this.field).subscribe(function(value){
                        // self.setEnable(value)
                        // })
                        this.dataModel.on(this.field + '.enable.' +  $.DataTable.ON_CURRENT_META_CHANGE, function(event){
                            self.setEnable(event.newValue);
                        });
                        this.setEnable(this.dataModel.isEnable(this.field))
                    } else {
                        this.dataModel.subscribe(function(value) {
                            self.modelValueChange(value)
                        })
                    }
                    this.modelValueChange(this.hasDataTable ? this.dataModel.getValue(this.field) : this.dataModel())
// this.modelValuelangChange(this.hasDataTable ?
// this.dataModel.getValue(this.fieldlang) : this.dataModel())
                }

            },
            parseDataModel: function() {
                if (!this.options || !this.options["data"]) return
                this.dataModel = $.getJSObject(this.viewModel, this.options["data"])
                if (this.dataModel instanceof $.DataTable) {
                    this.hasDataTable = true
                    this.field = this.options["field"]
                    // this.fieldlang = this.options["fieldlang"]
                }
            },
            // 往模型上设置值
            setModelValue: function(valObj) {
                if (!this.dataModel) return
                if (this.hasDataTable) {

                    this.dataModel.setValue(valObj.field, valObj.newValue)
                    // this.dataModel.setValue(this.fieldlang, valObj.lang)
                } else {
                    this.dataModel(valObj.newValue)
                }
            },
            modelValueChange: function(value) {

                var self = this
                if(this.multidata){

                    for(i = 0; i < self.multinfo.length; i++){
                        if(i){
                            self.multidata[i] = self.dataModel.getValue(self.field + (i+1),self.dataTableRow)
                        }else{
                            self.multidata[i] = self.dataModel.getValue(self.field,self.dataTableRow)
                        }
                    }
                    this.$element.multilang({"multidata":self.multidata});

                }



                // this.dataModel.getValue(this.field,this.dataTableRow)
                // $(this.element).siblings('.multilang_body').children('input').val(value)

            },
            modelValuelangChange: function(value) {

            },
            Statics: {
                compName: 'multilang'
            }
        })

        if ($.compManager)
            $.compManager.addPlug(Multilang)
    }($);
    +function($) {

        var Pagination = function(element, options, viewModel) {
            var oThis = this;

            this.id = options['id'];
            this.dataTable = $.getJSObject(viewModel, options["data"]);
            this.element = element;
            this.$element = $(element)

            if (!this.dataTable.pageSize() && options.pageSize)
                this.dataTable.pageSize(options.pageSize)
            options.pageSize = this.dataTable.pageSize() || options.pageSize
            this.$element.pagination(options);
            this.pagination = this.$element.data('u.pagination')
            this.pagination.dataTable = this.dataTable
            this.pageChange = $.getFunction(viewModel,options['pageChange']);
            this.sizeChange = $.getFunction(viewModel,options['sizeChange']);

            this.$element.on('pageChange', function(event,pageIndex) {
                if (typeof oThis.pageChange == 'function'){
                    oThis.pageChange(pageIndex);
                }else{
                    oThis.defaultPageChange(pageIndex);
                }
            })

            this.$element.on('sizeChange', function(event,size,pageIndex){
                if (typeof oThis.sizeChange == 'function'){
                    oThis.sizeChange(size,pageIndex);
                }else{
                    $.showMessageDialog("没有注册sizeChange事件")
                }
            })


            this.dataTable.totalPages.subscribe(function(value) {
                //modify by songhlc yuncai 没有数据不显示分页
                if(value&&((value-0)>1))
                    oThis.$element.css("display","inline-block");
                oThis.pagination.update({totalPages:value})
            })

            this.dataTable.pageSize.subscribe(function(value) {
                oThis.pagination.update({pageSize:value})
            })

            this.dataTable.pageIndex.subscribe(function(value) {
                oThis.pagination.update({currentPage:value+1})
            })
            this.$element.css("display","none");


        }

        Pagination.fn = Pagination.prototype

        Pagination.fn.defaultPageChange = function(pageIndex){
            // var pagesize =
            // parseInt($(event.target.lastChild).find(".page_z").val())
            // if(!typeof(pagesize)){
            // pagesize = options.pageSize
            // }
            // if(oThis.dataTable.pageSize() == pagesize) {
            // oThis.dataTable.cacheCurrentPage()
            // } else {
            // oThis.dataTable.clearCache()
            // }
            if(this.dataTable.hasPage(pageIndex)){
                this.dataTable.setCurrentPage(pageIndex)
            } else {
                // oThis.dataTable.removeAllRows()
                // if(viewModel['pageChange']) {
                // viewModel['pageChange'](pageIndex,pagesize)
                // }
            }
        };

        Pagination.fn.disableChangeSize = function(){
            this.pagination.disableChangeSize();
        };

        Pagination.fn.enableChangeSize = function(){
            this.pagination.enableChangeSize();
        };


        Pagination.getName = function() {
            return 'pagination'
        }

        if ($.compManager)
            $.compManager.addPlug(Pagination)

    }($);

    +function($) {

        /**
         * Class Editor
         *
         * @param {[type]}
         *            document [description]
         * @param {[type]}
         *            options [description]
         * @param {[type]}
         *            viewModel [description]
         */
        var Editor = $.InputComp.extend({
            initialize: function(element, options, viewModel) {

                this.element = element;
                this.id = options['id'];
                this.options = options;
                this.viewModel = viewModel;
                this.e_editor = this.id + "editor";
                this.render(this.options);

                Editor.superclass.initialize.apply(this, arguments)
                this.create()


            },

            render: function(data){
                var cols = data.cols || 80;
                var rows = data.rows || 10;
                var self = this
                var tpls = '<textarea cols="' + cols + '" id="'+ this.e_editor +'" name="editor" rows="' + rows + '"></textarea>';
                $(this.element).append(tpls);
                // this.element.append(tpls);
                $( '#'+this.e_editor ).ckeditor();
                var tmpeditor = CKEDITOR.instances[this.e_editor]
                this.tmpeditor = tmpeditor
                // tmpeditor.setData()
                this.tmpeditor.on('blur',function(){

                    self.setValue(tmpeditor.getData())
                });

                this.tmpeditor.on('focus',function(){

                    self.setShowValue(self.getValue())
                });

                // console.log(CKEDITOR.instances[this.e_editor].getData())
            },
            modelValueChange: function(value) {
                if (this.slice) return
                value = value || ""
                this.trueValue = value
                this.showValue = value// this.masker.format(value).value
                this.setShowValue(this.showValue)
            },
            setValue: function(value) {
                this.trueValue = value// this.formater.format(value)
                this.showValue = value// this.masker.format(value).value
                this.setShowValue(this.showValue)
                this.slice = true
                this.setModelValue(this.trueValue)
                this.slice = false
                this.trigger(Editor.EVENT_VALUE_CHANGE, this.trueValue)
            },
            getValue : function() {
                return this.trueValue
            },
            setShowValue : function(showValue) {
                this.showValue = showValue
                this.element.value = showValue
                this.tmpeditor.setData(showValue)
            },
            getShowValue: function() {
                return this.showValue
            },
            getContent: function(){
                return $( '#'+this.e_editor ).html();
            },

            setContent: function(txt){
                $( '#'+this.e_editor ).html(txt);
            },

            Statics: {
                compName: 'editor'
            }
        });

        if ($.compManager)
            $.compManager.addPlug(Editor)

    }($);

    +function($) {

        /**
         * link控件
         */
        var LinkComp = $.BaseComponent.extend({
            initialize: function(element, options, viewModel) {
                $.InputComp.superclass.initialize.apply(this, arguments)
                this.dataModel = null
                this.hasDataTable = false
                this.enable = true
                this.parseDataModel()
                if(options['click']){
                    var clickFunc  = $.getJSObject(viewModel, options['click'])
                    this.on('click', clickFunc)
                }

                this.create()
            },
            create: function() {
                var self = this
                if (this.dataModel) {
                    // 处理数据绑定
                    if (this.hasDataTable) {
                        // this.dataModel.ref(this.field).subscribe(function(value)
                        // {
                        // self.modelValueChange(value)
                        // })
                        this.dataModel.on(this.field + '.' +  $.DataTable.ON_CURRENT_VALUE_CHANGE, function(event){
                            self.modelValueChange(event.newValue);
                        });

                        // 处理只读
                        // this.dataModel.refEnable(this.field).subscribe(function(value){
                        // self.setEnable(value)
                        // })
                        this.dataModel.on(this.field + '.enable.' +  $.DataTable.ON_CURRENT_META_CHANGE, function(event){
                            self.setEnable(event.newValue);
                        });

                        this.dataModel.on($.DataTable.ON_CURRENT_ROW_CHANGE, function(){
                            var row = self.dataModel.getCurrentRow();
                            if (!row){
                                self.modelValueChange('');
                                self.setEnable(false);
                            }else{
                                self.modelValueChange(row.getValue(self.field));
                            }
                        });


                        this.setEnable(this.dataModel.isEnable(this.field))
                    } else {
                        this.dataModel.subscribe(function(value) {
                            self.modelValueChange(value)
                        });
                    }
                    this.modelValueChange(this.hasDataTable ? this.dataModel.getValue(this.field) : this.dataModel())
                }
                $(this.element).on('click', function(){
                    if (self.enable)
                        self.trigger('click', {field:self.field,dataTable:self.dataModel})
                })
            },
            /**
             * 模型数据改变
             *
             * @param {Object}
             *            value
             */
            modelValueChange: function(value) {
                this.setValue(value)
            },

            /**
             * @private
             */
            parseDataModel: function() {
                if (!this.options || !this.options["data"]) return
                this.dataModel = $.getJSObject(this.viewModel, this.options["data"])
                if (this.dataModel instanceof $.DataTable) {
                    this.hasDataTable = true
                    this.field = this.options["field"]
                }
            },
            /**
             * 设置控件值
             *
             * @param {Object}
             *            value
             */
            setValue: function(value) {
                this.value = value
                $(this.element).html(value)
            },
            /**
             * 取控件的值
             */
            getValue: function() {
                return this.value
            },
// setUrl: function(url){
//
// },
// getUrl: function(){
//
// }

            setEnable: function(enable){
                if(enable === true || enable === 'true'){
                    this.enable = true
                    $(this.element).css('cursor', 'pointer')
                }
                else if(enable === false || enable === 'false'){
                    this.enable = false
                    $(this.element).css('cursor', 'not-allowed')
                }
            },

            Statics: {
                compName: 'link'
            }
        })

        if ($.compManager)
            $.compManager.addPlug(LinkComp)

    }($);

    + function($) {

        var Textarea = $.InputComp.extend({
            initialize: function(element, options, viewModel) {
                var self = this
                Textarea.superclass.initialize.apply(this, arguments)
                this.create()

                if (this.element.nodeName == 'TEXTAREA') {
                    $(this.element).focusin(function(e) {
                        self.setShowValue(self.getValue())
                    })
                    $(this.element).blur(function(e) {
                        self.setValue(self.element.value)
                    })
                }
            },

            modelValueChange: function(value) {
                if (this.slice) return
                value = value || ""
                this.trueValue = value
                this.showValue = value // this.masker.format(value).value
                this.setShowValue(this.showValue)
            },
            setValue: function(value) {
                this.trueValue = value // this.formater.format(value)
                this.showValue = value // this.masker.format(value).value
                this.setShowValue(this.showValue)
                this.slice = true
                this.setModelValue(this.trueValue)
                this.slice = false
                this.trigger(Textarea.EVENT_VALUE_CHANGE, this.trueValue)
            },
            getValue: function() {
                return this.trueValue
            },
            setShowValue: function(showValue) {
                this.showValue = showValue
                this.element.value = showValue
                this.element.title = showValue
            },
            getShowValue: function() {
                return this.showValue
            },


            Statics: {
                compName: 'textarea'
            }
        })

        if ($.compManager)
            $.compManager.addPlug(Textarea)

    }($);
    +function($) {

        /**
         * 百分比控件
         */
        var PercentComp = $.InputComp.extend({
            initialize: function(element, options, viewModel) {
                var self = this
                PercentComp.superclass.initialize.apply(this, arguments)
                this.validType = 'float'
                this.max = options['max']
                this.min = options['min']
                this.maxNotEq = options['maxNotEq']
                this.minNotEq = options['minNotEq']
                if (this.dataModel) {
                    if (this.hasDataTable) {
                        this.min = this.dataModel.getMeta(this.field, "min") !== undefined ? this.dataModel.getMeta(this.field, "min") : this.min
                        this.max = this.dataModel.getMeta(this.field, "max") !== undefined ? this.dataModel.getMeta(this.field, "max") : this.max
                        this.minNotEq = this.dataModel.getMeta(this.field, "minNotEq") !== undefined ? this.dataModel.getMeta(this.field, "minNotEq") : this.minNotEq
                        this.maxNotEq = this.dataModel.getMeta(this.field, "maxNotEq") !== undefined ?  this.dataModel.getMeta(this.field, "maxNotEq") : this.maxNotEq

                    }
                }
                this.masker = new PercentMasker();
                this.create()
            },
            modelValueChange: function(value) {
                if (this.slice) return
                value = value || ""
                this.trueValue = value
                this.showValue = this.masker.format(value).value
                this.setShowValue(this.showValue)
            },
            setValue: function(value) {
                this.trueValue = value // this.formater.format(value)
                this.showValue = this.masker.format(value).value
                this.setShowValue(this.showValue)
                this.slice = true
                this.setModelValue(this.trueValue)
                this.slice = false
                this.trigger(PercentComp.EVENT_VALUE_CHANGE, this.trueValue)
            },
            getValue : function() {
                return this.trueValue
            },
            setShowValue : function(showValue) {
                this.showValue = showValue
                this.element.value = showValue
            },
            getShowValue: function() {
                return this.showValue
            },

            Statics: {
                compName: 'percent'
            }
        })

        if ($.compManager)
            $.compManager.addPlug(PercentComp)

    }($);
// yuncai liangchen1
    +function($) {
        /**
         * 按钮组件，用于根据单据状态控制按钮可用性
         */
        var ButtonComp = $.BaseComponent.extend({
            initialize: function(element, options, viewModel) {
                ButtonComp.superclass.initialize.apply(this, arguments)
                this.dataModel = null
                this.hasDataTable = false
                this.approvefield = options["approvefield"]
                this.visibleBillStatus = this.options["visibleBillStatus"]
                this.parseDataModel()
                this.create()
            },
            create: function() {
                var self = this
                if (this.dataModel) {
                    // 处理数据绑定
                    if (this.hasDataTable) {
                        this.dataModel.on(this.field+"."+$.DataTable.ON_VALUE_CHANGE, function(params){
                            self.assert(params);
                        });
                        if(this.approvefield!=null){
                            this.dataModel.on(this.approvefield+"."+$.DataTable.ON_VALUE_CHANGE, function(params){
                                self.assert(params);
                            });
                        }
                        this.dataModel.on($.DataTable.ON_INSERT, function(params){
                            self.assert(params);
                        });

                    }
                }
            },
            parseDataModel: function() {
                if (!this.options || !this.options["data"]) return
                this.dataModel = $.getJSObject(this.viewModel, this.options["data"])
                if (this.dataModel instanceof $.DataTable) {
                    this.hasDataTable = true
                    this.field = this.options["field"]
                }
            },
            assert: function(params){
                var self = this;
                if(self.visibleBillStatus){
                    for(var i=0;i<self.visibleBillStatus.length;i++)
                    {  // 业务状态
                        var status = params.rows[0].data[self.field].value;
                        if(self.approvefield==null){
                            // 处理流程按钮可用性
                            if(self.visibleBillStatus){
                                for(var i=0;i<self.visibleBillStatus.length;i++)
                                {
                                    var status = params.rows[0].data[self.field].value;
                                    if(status==self.visibleBillStatus[i]){
                                        self.setEnable(true);
                                        break;
                                    }
                                    self.setEnable(false);
                                }
                            }
                        }else{
                            // 审批流状态
                            approvestatus = params.rows[0].data[self.approvefield].value;
                            var visibleStatus = self.visibleBillStatus[i];
                            var spl = '&&';
                            if(visibleStatus.indexOf(spl)==-1){
                                if(status==self.visibleBillStatus[i]||approvestatus==(self.visibleBillStatus[i]!=null?self.visibleBillStatus[i]:null)){
                                    self.setEnable(true);
                                    break;
                                }
                            }else{
                                visibleStatus = visibleStatus.split(spl);
                                if(status==visibleStatus[0]&&approvestatus==(visibleStatus[1]!=""?visibleStatus[1]:null)){
                                    self.setEnable(true);
                                    break;
                                }
                            }
                            self.setEnable(false);
                        }
                    }
                }
            },
            setEnable: function(enable) {
                if(enable){
                    var id = $(this.element).css("display","inline-block");
                }else{
                    $(this.element).css('display',"none")
                }
            },
            Statics: {
                compName: 'button'
            }
        })
        $.ButtonComp = ButtonComp
        if ($.compManager)
            $.compManager.addPlug(ButtonComp)

    }($);
    +function( $, ko) {
        'use strict'
        var App = function(){
            this.dataTables = {}
// this.comps = {}
        }

        App.fn = App.prototype

        App.fn.init = function(viewModel, element, doApplyBindings){
            var self = this;
            element = element || document.body
            if (!$.isArray(element)){
                element = [element];
            }
            this.elements = element;
            $.each(this.elements, function(i, element){
                $(element).find('[u-meta]').each(function() {
                    if ($(this).data('u-meta')) return
                    if ($(this).parents('[u-meta]').length > 0) return
                    var options = JSON.parse($(this).attr('u-meta'))
                    if(options && options['type']) {
                        if (self.adjustFunc)
                            self.adjustFunc.call(self, options);
                        var comp = $.compManager._createComp(this, options, viewModel, self)
                        if (comp)
// this.comps[comp.getId()] = comp
                            $(this).data('u-meta', comp)
                    }
                })
                if ($.hotkeys)
                    $.hotkeys.scan(element)
                try{
                    if (typeof doApplyBindings == 'undefined' || doApplyBindings == true)
                        ko.applyBindings(viewModel, this)
                }catch(e){
                    iweb.log.error(e)
                }
            })

            _getDataTables(this, viewModel)
// ko.cleanNode(this.element)
        }

        App.fn.setAdjustMetaFunc = function(adjustFunc){
            this.adjustFunc = adjustFunc
        }

        App.fn.addDataTable = function(dataTable){
            this.dataTables[dataTable.id] = dataTable
            return this
        }
        App.fn.getDataTable = function(id){
            return this.dataTables[id]
        }

        App.fn.getDataTables = function(){
            return this.dataTables
        }

        App.fn.getComp = function(compId){
            var returnComp = null;
            $.each(this.elements, function(i,element){
                $(element).find('[u-meta]').each(function() {
                    if ($(this).data('u-meta')){
                        var comp = $(this).data('u-meta');
                        if (comp.id === compId){
                            returnComp = comp;
                            return false;
                        }
                    }
                })
            })
            return returnComp;
        }

        App.fn.getCompsByDataTable = function(dataTableId,element){
            var comps = this.getComps(element),
                targetComps = []
            for (var i=0; i<comps.length; i++){
                if ((comps[i].dataModel && comps[i].dataModel['id'] == dataTableId) || (comps[i].dataTable && comps[i].dataTable['id'] == dataTableId))
                    targetComps.push(comps[i])
            }
            return targetComps
        }

        /**
         * 获取某区域中的所有控件
         *
         * @param {object}
         *            element
         */
        App.fn.getComps = function(element){
            var elements = element ? element : this.elements;
            var returnComps = [];
            if(!$.isArray(elements))
                elements = [elements];
            $.each(elements,function(i, element){
                $(element).find('[u-meta]').each(function() {
                    if ($(this).data('u-meta')){
                        var comp = $(this).data('u-meta')
                        if (comp)
                            returnComps.push(comp);
                    }
                })
            })
            return returnComps;
        }

        /**
         * 控件数据校验
         *
         * @param {Object}
         *            element
         */
        App.fn.compsValidate = function(element){
            var comps = this.getComps(element),
                passed = true
            for(var i=0; i< comps.length; i++){
                if (comps[i].doValidate)
                    passed = comps[i].doValidate(true) && passed
            }
            return passed
        }

        /**
         * 根据类型获取控件
         *
         * @param {String}
         *            type
         * @param {object}
         *            element
         */
        App.fn.getCompsByType = function(type,element){
            var elements = element ? element : this.elements;
            var returnComps = [];
            if(!$.isArray(elements))
                elements = [elements];
            $.each(elements, function(i,element){
                $(element).find('[u-meta]').each(function() {
                    if ($(this).data('u-meta')){
                        var comp = $(this).data('u-meta')
                        if (comp && comp.type == type)
                            returnComps.push(comp);
                    }
                })
            })
            return returnComps;
        }


        App.fn.getEnvironment = function(){
            return window.iweb.Core.collectEnvironment()
        }

        App.fn.setClientAttribute = function(k,v){
            window.iweb.Core.setClientAttribute(k,v)
        }

        App.fn.getClientAttribute = function(k){
            return window.iweb.Core.getClientAttributes()[k]
        }

        App.fn.serverEvent = function(){
            return new ServerEvent(this)
        }

        App.fn.ajax = function(params){
            params = this._wrapAjax(params)
            $.ajax(params)
        }

        App.fn._wrapAjax = function(params){
            var self = this
            var orignSuccess =  params.success
            var orignError =  params.error
            var deferred =  params.deferred;
            if(!deferred || !deferred.resolve){
                deferred = {resolve:function(){},reject:function(){}}
            }
            params.success = function(data,state,xhr){
                if(processXHRError(self,data,state,xhr)){
                    orignSuccess.call(null, data)
                    self._successFunc(data, deferred)
                }else{
                    deferred.reject();
                }
            }
            params.error=function(data,state,xhr){
                if(processXHRError(self,data,state,xhr)){
                    orignError.call(null, data)
                    self._successFunc(data, deferred)
                }else{
                    deferred.reject();
                }
            }
            if(params.data)
                params.data.environment=ko.utils.stringifyJson(window.iweb.Core.collectEnvironment());
            else
                params.data = {environment:ko.utils.stringifyJson(window.iweb.Core.collectEnvironment())}
            return params
        }

        App.fn._successFunc = function(data, deferred){
            deferred.resolve();
        }

        window.processXHRError  = function (rsl,state,xhr) {
            if(typeof rsl ==='string')
                rsl = JSON.parse(rsl)
            if(xhr.getResponseHeader && xhr.getResponseHeader("X-Error")){
                $.showMessageDialog({type:"info",title:"提示",msg: rsl["message"],backdrop:true});
                if(rsl["operate"]){
                    eval(rsl["operate"]);
                }
                return false;
            }
            return true;
        };

        App.fn.setUserCache = function(key,value){
            var userCode = this.getEnvironment().usercode;
            if(!userCode)return;
            localStorage.setItem(userCode+key,value);
        }

        App.fn.getUserCache = function(key){
            var userCode = this.getEnvironment().usercode;
            if(!userCode)return;
            return localStorage.getItem(userCode+key);
        }

        App.fn.removeUserCache = function(key){
            var userCode = this.getEnvironment().usercode;
            if(!userCode)return;
            localStorage.removeItem(userCode+key);
        }

        App.fn.setCache = function(key,value){
            localStorage.setItem(key,value);
        }

        App.fn.getCache = function(key){
            return localStorage.getItem(key);
        }

        App.fn.removeCache = function(key){
            localStorage.removeItem(key)
        }

        App.fn.setSessionCache = function(key,value){
            sessionStorage.setItem(key,value)
        }

        App.fn.getSessionCache = function(key){
            return sessionStorage.getItem(key)
        }

        App.fn.removeSessionCache = function(key){
            sessionStorage.removeItem(key)
        }

        App.fn.setEnable = function(enable){
            $.each(this.elements, function(i, element){
                $(element).find('[u-meta]').each(function() {
                    if ($(this).data('u-meta')){
                        var comp = $(this).data('u-meta')
                        if (comp.setEnable)
                            comp.setEnable(enable)
                    }
                })
            })
        }

        var ServerEvent = function(app){
            this.app = app
            this.datas = {}
            this.params = {}
            this.event = null
            this.ent = window.iweb.Core.collectEnvironment()
            if(!iweb.debugMode) {
                this.compression = true
            }
        }

        ServerEvent.DEFAULT = {
            async: true,
            singleton: true,
            url: (window.$ctx || '/iwebap') + '/evt/dispatch'
        }

        ServerEvent.fn = ServerEvent.prototype

        ServerEvent.fn.addDataTable = function(dataTableId, rule){
            var dataTable = this.app.getDataTable(dataTableId)
            this.datas[dataTableId] = dataTable.getDataByRule(rule)
            return this
        }

        ServerEvent.fn.setCompression = function(compression){
            if (!iweb.browser.isIE8 && !window.pako && compression == true)
                iweb.log.error("can't compression, please include  pako!")
            else
                this.compression = compression
        }

        /**
         *
         * @param {Object}
         *            dataTabels 格式1: ['dt1',{'dt2':'all'}]，格式2：['dt1', 'dt2']，格式3:
         *            ['dt1', 'dt2'], 'all'，格式4：'dt', all
         */
        ServerEvent.fn.addDataTables = function(dataTables){
            if($.type(dataTables) == 'string') {
                // 只传入了一个datatable
                this.addDataTable(dataTables[i], arguments[1])
            }
            if(arguments.length == 2) {
                for(var i = 0; i<dataTables.length; i++){
                    var rule;
                    if(typeof arguments[1] == 'string') {
                        rule = arguments[1]
                    } else if($.type(arguments[1]) == 'array') {
                        rule = arguments[1][i]
                    }
                    this.addDataTable(dataTables[i], rule)
                }
            } else {
                for(var i = 0; i<dataTables.length; i++){
                    var dt = dataTables[i]
                    if (typeof dt == 'string')
                        this.addDataTable(dt)
                    else{
                        for (var key in dt)
                            this.addDataTable(key, dt[key])
                    }
                }
            }

            return this
        }

        ServerEvent.fn.addAllDataTables = function(rule){
            var dts = this.app.dataTables
            for (var i = 0; i< dts.length; i++){
                this.addDataTable(dts[i].id, rule)
            }
        }


        ServerEvent.fn.addParameter = function(key,value){
            this.params[key] = value
            return this
        }

        ServerEvent.fn.setEvent = function(event){
            // 无用逻辑
            // if (true)
            // this.event = event
            // else
            this.event = _formatEvent(event)
            return this
        }

        var _formatEvent = function(event){
            return event
        }


// app.serverEvent().fire({
// ctrl:'CurrtypeController',
// event:'event1',
// success:
// params:
// })
        ServerEvent.fn.fire = function(p){
            var self = this
// params = $.extend(ServerEvent.DEFAULT, params);
            var data = this.getData()
            data.parameters = ko.utils.stringifyJson(this.params)
            var params = {
                type: p.type ||  "POST",
                data: p.params || {},
                url: p.url || ServerEvent.DEFAULT.url,
                async: typeof p.async == 'undefined' ? ServerEvent.DEFAULT.async : p.async,
                singleton: p.singleton || ServerEvent.DEFAULT.singleton,
                success: p.success,
                renderData: p.renderData,
                error: p.error,
                dataType:'json',
                preSuccess: p.preSuccess
            }
            params.data.ctrl = p.ctrl
            params.data.method = p.method
            if (this.event)
                params.data.event = ko.utils.stringifyJson(this.event)
            var preSuccess = params.preSuccess || function(){}
            var orignSuccess =  params.success || function(){}
            var renderData = params.renderData || null
            var orignError = params.error // || function(){}
            this.orignError = orignError
            var deferred =  params.deferred;
            if(!deferred || !deferred.resolve){
                deferred = {resolve:function(){},reject:function(){}}
            }
            params.success = function(data,state,xhr){
                if(processXHRError(self, data,state,xhr)){
                    preSuccess.call(null, data)
                    // modify by songhlc 添加自定义成功函数renderData ,采用自定义的renderData代替原来的客户端setData方法(解决行数过多引起的效率问题)
                    if (renderData) {
                        renderData(data, data.custom)
                    } else {
                        self._successFunc(data, deferred)
                    }
                    orignSuccess.call(null, data.custom)
                    deferred.resolve();
                }else{
                    deferred.reject();
                }
            }
            params.error=function(data,state,xhr){
                if(processXHRError(self, data,state,xhr)){
                    if (orignError){
                        //add by songhlc yuncai 原来如果报错则不能正确返回
                        if(data.custom){
                            orignError.call(null, data.custom)
                        }
                        else{
                            // songhlc 添加统一306未登录提示
                            var responseJSON = data.responseJSON
                            if (responseJSON.msg && responseJSON.msg.indexOf('auth check error')>=0) {
                                setTimeout(function(){
                                    window.TOASTR.error('登录超时，请尝试重新登录！')
                                },200)
                            } else if (responseJSON._message) {
                                setTimeout(function(){
                                    window.TOASTR.error(responseJSON._message)
                                },200)
                            }
                            orignError.call(null, data.responseJSON)
                        }
                    }
                    else{
                        if (data.status == 404) {
                            var errormsg = data.responseJSON?data.responseJSON._message:"服务器开小差了，请稍后重试";
                            setTimeout(function(){
                                window.TOASTR.error(errormsg)
                            },200)
                        } else if (data.responseJSON.msg && data.responseJSON.msg.indexOf('auth check error')>=0) {
                            setTimeout(function(){
                                window.TOASTR.error('登录超时，请尝试重新登录！')
                            },200)
                        } else {
                            var errormsg = data.responseJSON?data.responseJSON._message:"服务器开小差了，请稍后重试";
                            setTimeout(function(){
                                window.TOASTR.error(errormsg)
                            },200)
                        }
                    }


// self._successFunc(data, deferred)
                }else{
                    deferred.reject();
                }
            }
            params.data = $.extend(params.data,data);
            $.ajaxSetup({cache:false})
            params.beforeSend = function(request) {
                request.setRequestHeader("Cache-Control","no-cache");
            }
            $.ajax(params)

        }

        ServerEvent.fn.getData = function(){
            var envJson = ko.utils.stringifyJson(this.app.getEnvironment()),
                datasJson = ko.utils.stringifyJson(this.datas),
                compressType = '',
                compression = false
            if(window.trimServerEventData){
                datasJson = window.trimServerEventData(datasJson);
            }
            if (this.compression){
                if(!iweb.browser.isIE8 && window.pako) {
                    envJson = encodeBase64(window.pako.gzip(envJson))
                    datasJson = encodeBase64(window.pako.gzip(datasJson))
                    compression = true
                    compressType = 'gzip'
                }
            }
            return 	{
                environment: envJson,
                dataTables: datasJson,
                compression: compression,
                compressType: compressType
            }
        }

        ServerEvent.fn._successFunc = function(data, deferred){
            var dataTables = data.dataTables
            var dom = data.dom
            if (dom)
                this.updateDom(JSON.parse(dom))
            if (dataTables)
                this.updateDataTables(dataTables, deferred)
        }

        ServerEvent.fn.updateDataTables = function(dataTables, deferred){
            for (var key in dataTables){
                var dt = this.app.getDataTable(key)
                if (dt) {
                    dt.setData(dataTables[key])
                    dt.updateMeta(dataTables[key].meta)
                }
            }
        }

        ServerEvent.fn.setSuccessFunc = function(func){
            this._successFunc = func
        }

        ServerEvent.fn.updateDom = function(){
            $.each( dom, function(i, n){
                var vo = n.two
                var $key = $(n.one)
                _updateDom($key, vo)
            });
        }

        function _updateDom($key, vos){
            for (var i in vos){
                var vo = vos[i]
                for (var key in vo){
                    var props = vo[key]
                    if (key == 'trigger'){
                        $key.trigger(props[0])
                    }
                    else{
                        if ($.isArray(props)){
                            $.each(props, function(i, n){
                                $key[i](n)
                            });
                        }
                        else
                            try{
                                $key[i](vo)
                            }catch(error){
                                $key[i](vo[i])
                            }
                    }
                }
            }
        }

        var processXHRError  = function (self, rsl,state,xhr) {
            if(typeof rsl ==='string')
                rsl = JSON.parse(rsl)
            //modify by songhlc 后端com.yonyou.iuap.iweb.exception.WebRuntimeException;jar包冲突 添加status判断 切统一报错方法
            if(rsl.status == 0 || (xhr.getResponseHeader && xhr.getResponseHeader("X-Error"))){
                if (self.orignError)
                    self.orignError.call(self,rsl,state,xhr)
                else{
                    setTimeout(function(){
                        window.TOASTR.error(rsl.msg)
                    },200)
                }
                return false;
            }
            return true;
        };

        $.createApp = function(){
            var app = new App()
            return app
        }

        var _getDataTables = function(app, viewModel){
            for(var key in viewModel){
                if (viewModel[key] instanceof $.DataTable){
                    viewModel[key].id = key
                    viewModel[key].parent = viewModel
                    app.addDataTable(viewModel[key])
                }
            }
        }
    }($, ko);


    +function($){
        'use strict'
        var Event = {
            fire: function(eventName){
                eventName = eventName.toLowerCase();
                if (!window._events || !window._events[eventName]) return
                var args =  Array.prototype.slice.call(arguments, 1);
                var events = window._events[eventName];
                var ctx = {stop:false, returnValues:{}}
                args.unshift(ctx)
                for (var i = 0, count = events.length; i < count; i++) {
                    var callback = events[i].callback
                    ctx.nameSpace = callback.nameSpace
                    callback.apply(this, args);
                    if (args[0].stop == true)
                        break;
                }
                return args[0].returnValues;
            },
            on: function(eventName, nameSpace, callback){
                if (typeof nameSpace == 'function'){
                    callback = nameSpace
                    nameSpace = ''
                }
                callback.nameSpace = nameSpace
                eventName = eventName.toLowerCase()
                window._events = window._events || {}
                var events = window._events[eventName] || (window._events[eventName] = [])
                events.push({
                    callback: callback
                })
            },
            remove: function(eventName, nameSpace){
                window._events = window._events || {}
                var events = window._events[eventName]
                if (!events) return
                if (!nameSpace)
                    window._events[eventName] = []
                else
                    for (var i = 0, count = events.length; i < count; i++) {
                        if (events[i].callback.nameSpace == nameSpace)
                            events.splice(i,1)
                    }
            }
        };

        $.compEvent = Event;

    }($);
}));